(二)inlineCallbacks,同步方式写异步代码
一、 上篇提到了用defered对象注册回调的方式,来处理异步操作,这样大家都知道,实际情况代码很难搞的。因为当业务逻辑复杂后,这边一个异步操作,我们注册一个回调,代码跳到A地方,A里面也有异步操作,注册回调,然后跳到B,自己看起来都晕,维护起来不方便,不好读也不好排错,这时候,如果有简单的方式就更好了,能提高书写效率。
类似于tornado的gen.coroutine,我们可以用@inlineCallbacks装饰器,配合yield关键字,将代码结构变成同步的。
二、在@inlineCallbacks装饰的情况下,先看这几点:
1. deferred对象的结果,也就是异步操作完成后的返回结果,这个返回结果正常是传递给了callback,我们通过yield deferred可以拿到
2. 下层callback的返回值即作为上层callback的参数,直至最外层。
# coding:utf-8 import time from twisted.internet import defer, reactor from twisted.internet.defer import inlineCallbacks, returnValue class deferTester(): def __init__(self): self.d = defer.Deferred() #模拟耗时操作 @inlineCallbacks def work(self): print "[%s] 模拟耗时网络IO, 等待3秒" % nowtime() time.sleep(3) retult = yield('haha')#非延迟对象会立即返回 print "[%s] result = "%nowtime(),retult reactor.callLater(2, self.d.callback, retult) self.d.addCallback(self.first_call) self.d.addCallback(self.second_call) def first_call(self, x): print "[%s] inner调用,接收参数 = " % nowtime(), x return 5 #返回的值作为之后callback的参数 def second_call(self, x): print "[%s] nest调用,接收参数 = " % nowtime(), x def stop(): reactor.stop() print "[%s] 停止reactor"%nowtime() def nowtime(): return time.strftime('%Y-%m-%d,%X', time.localtime()) if __name__ == '__main__': print "[%s] 开始测试 "%nowtime() tester = deferTester() reactor.callWhenRunning(tester.work)#reactor调用耗时任务 print "[%s] 启动reactor "%nowtime() reactor.callLater(8, stop) #5秒后停止reactor线程 reactor.run()
打印结果为:
[2018-10-25,18:13:13] 开始测试 [2018-10-25,18:13:13] 启动reactor [2018-10-25,18:13:13] 模拟耗时网络IO, 等待3秒 [2018-10-25,18:13:16] result = haha [2018-10-25,18:13:18] first_call,接收参数 = haha [2018-10-25,18:13:18] second_call,接收参数 = 5 [2018-10-25,18:13:21] 停止reactor
可以看出,first_call的返回值5作为second_call的入参
我们稍微修改下测试类如下:
#模拟耗时操作 @inlineCallbacks def work(self): print "[%s] 模拟耗时网络IO, 等待3秒" % nowtime() time.sleep(3) retult = yield('haha')#非延迟对象会立即返回 print "[%s] result = "%nowtime(),retult reactor.callLater(2, self.d.callback, retult) self.d.addCallback(self.inner_work) res = yield self.d #此时d对象调用inner_work,返回结果为5 print "[%s] res = "%nowtime(),res @inlineCallbacks def inner_work(self, x): print "[%s] inner调用,接收参数 = " % nowtime(), x yield returnValue(5) #生成器中不能用return返回结果
结果为:
[2018-10-25,18:15:05] 开始测试 [2018-10-25,18:15:05] 启动reactor [2018-10-25,18:15:05] 模拟耗时网络IO, 等待3秒 [2018-10-25,18:15:08] result = haha [2018-10-25,18:15:10] inner调用,接收参数 = haha [2018-10-25,18:15:10] res = 5 [2018-10-25,18:15:13] 停止reactor
如果用了inlineCallback, 返回的是一个生成器,此时不能用简单的return,twisted有returnValue可以使用