延迟(Defer)机制时Twisted框架中实现异步编程的体系,使得程序设计可以采用事件驱动的机制
Defer
可以将Twisted中的Defer看作一个管理回调函数的对象,开发者可以向该函数添加需要回调的函数,同时可以指定该组函数何时被调用
- addCallback(self,callback,*args,**kw):添加正常处理回调函数,其中callback是回调函数名,args和kw是传递给回调函数的参数。其中回调函数至少应该具有一个输入参数
- addErrback(self,callback,*args,**kw):添加错误处理回调函数
- addBoth(self,callback,*args,**kw):一个回调函数同时作为正常、异常处理的回调函数
- chainDeferred(self,d):将另外一个Defer对象(参数d)的正确、错误处理函数添加到当前Defer对象中。本函数具有单向性。(当前Defer调用回调函数不会导致另外一个Defer对象(参数d)的回调函数被调用)
- callback(self,result):调用正常处理函数链,其中result是传递给第一个正常回调函数的参数。
- errback(self,fail=None):调用异常处理函数链,其中fail是传递给第一个异常回调函数的参数。
- pause(self)/unpause(self):暂停、继续对象调用链
Defer对象的回调函数只能由callback()、errback()进行一次调用。如果试图二次调用,框架会抛出异常。
reactor
callLater是Twisted中关键的异步调用函数
- callLater(delay,callable,*args,**kw):参数delay定义延时调用的秒数,callable参数是回调函数,args、kw是参数
- stop():终止reactor.run()的挂起
- run():挂起运行
# coding:utf8
from twisted.internet import reactor,defer
d =defer.Deferred()
def print_square(d):
print('square of %d is %d'%(d,d*d))
return d
def print_twice(d):
print('twice of %d is %d'%(d,2*d))
return d
def process_error(f):
print('error when process')
def make_defer():
d.addCallback(print_square)
d.addCallback(print_twice)
d.addErrback(process_error)
reactor.callLater(2,d.callback,5)
make_defer()
reactor.run()
# 输出:(注册的两个回调函数都被调用)
# square of 5 is 25
# twice of 5 is 10
# coding:utf8
from twisted.internet import reactor
# 定义4秒钟后调用reactor.stop()
reactor.callLater(4,reactor.stop)
reactor.run()
print('Program finished!')
deferToThread
threads.deferToThread 创建Defer,在指定函数执行结束后自动调用callback函数,实现异步编程模式
可以调用Defer的addTimeout添加超时处理函数
addTimeout(timeout, clock, onTimeoutCancel=None)
timeout :超时时间
clock:twisted.internet.interfaces.IReactorTime,可以使用reactor
onTimeoutCancel:超时回调函数
from twisted.internet import reactor, threads
import time
def doLongCalculation(x):
# .... do long calculation here ...
time.sleep(5)
return 3*9
def printResult(x):
print(x)
def logTimeout(result, timeout):
'''
defer 超时处理
:param result: 执行超时的函数句柄
:param timeout: 超时时间(秒)
:return:
'''
print("Got {0!r} but actually timed out after {1} seconds".format(
result, timeout))
return result + " (timed out)"
d = threads.deferToThread(doLongCalculation,9)
d.addTimeout(2,reactor,logTimeout) # 添加超时处理函数,必须在addCallback函数前调用!!!
d.addCallback(printResult)
reactor.run()