(二)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可以使用

猜你喜欢

转载自www.cnblogs.com/mactec/p/9851772.html