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

  • 相关阅读:
    Flume
    nodejs中npm工具自身升级
    Nodejs v4.x.0API文档学习(1)简介
    nodejs设置NODE_ENV环境变量(1)
    nodejs使用express4框架默认app.js配置说明
    mongodb2.X添加权限
    javascript中new Date浏览器兼容性处理
    Android Studio中文组(中文社区)
    Javascript日期处理类库Moment.js
    android 按两次返回键退出应用
  • 原文地址:https://www.cnblogs.com/mactec/p/9851772.html
Copyright © 2020-2023  润新知