上文提到使用deferred对象很容易陷入回调地狱中,好在python提供yield生成器语法,可以很容易就包装一套更加友好的
异步编程API。就如同ES6提供的Promise等。
目前在Twisted中提供了一个inlineCallbacks装饰器。能简化多Deferred操作,先上代码:
from twisted.internet.defer import inlineCallbacks, Deferred, returnValue
from twisted.python.failure import Failure
from twisted.internet import reactor, defer
def loadRemoteData(callback):
import time
time.sleep(1)
callback(1)
def loadRemoteData2(callback):
import time
time.sleep(1)
callback(2)
@defer.inlineCallbacks
def getRemoteData():
d1 = defer.Deferred()
reactor.callInThread(loadRemoteData,d1.callback)
r1 = yield d1
d2 = defer.Deferred()
reactor.callInThread(loadRemoteData2,d2.callback)
r2 = yield d2
returnValue(r1+r2)
def getResult(v):
print "result=",v
if __name__ == '__main__':
d=getRemoteData()
d.addCallback(getResult)
reactor.callLater(4, reactor.stop);
reactor.run()
上例中涉及了两个Deferred对象,使用inlineCallbacks装饰器和yield语法,可以用类同步的语法来进行异步编程。
首先说一下Deferred完成是怎么回事,一个Deferred就相对于一个延迟任务的封装。当调用Deferred的callback或errback时,就代表
该异步任务已完成,而callback方法传入的参数就是Defered的结果。
上例中在r1=yield d1中会暂停,inlinecallbacks装饰器实际上就是调用yield的next来获取结果的,等d1 deferred完成后再继续进行下一步操作。
因此我们就实现了类同步语法来进行异步编程的目的,而不必使用嵌套回调等。
最后再通过returnValue(r1+r2)将计算结果返回。如果在py3中,则可以直接return r1+r2