zoukankan      html  css  js  c++  java
  • (一)使用twisted Deferred

    一、开篇

      为什么是twisted,twisted作为一个python网络编程框架,出道早,但一直不温不火,这几年和tornado比起来,更是近乎销声匿迹;但作为初学者,觉得twisted还是有很多优点值得去学习的,其优秀的性能(对python框架)其实更适合做底层的tcp server,而且个人觉得twisted deferred的设计思路非常简单清晰,相较于tornado future异步更好理解,缺点可能就是源码不好读,然后如果拿来直接开发web不是很方便。但还是那句话,twisted flask tornado gevent都有自己比较鲜明的特征,值得去学习下。

      博主也是初学,写这个博客也是想作为一个学习记录,如果有问题大家可以一起探讨,有出错的地方还请指出,谢谢。

    二、认识Deferred

      Deferred是一个延迟加载对象,这个概念类似于tornado future,是调用异步操作返回的一个对象,其中包括了操作成功后的回调处理,错误后的回调处理。

      简单讲,当我们需要执行一个耗时操作,比如下载某个大图片,此时用twisted的异步http请求,会给我们返回一个Deferred对象,让我们可以不用在这等图片下载完成,当前线程不会阻塞,而是可以去处理别的逻辑。twisted有一个底层event loop(类似tornado ioloop)处理线程),等图片下载完成后,会去自动触发Deferred的回调操作,这个细节我们不需要操作,我们要做的,就是添加这个回调逻辑,也就是常说的注册回调。

      下面有个简单例子

    # coding:utf-8
    
    import time
    
    from twisted.internet import defer, reactor
    
    class deferTester():
    
        def __init__(self):
            self.d = defer.Deferred()
    
        def getDefer(self):
            return self.d
    
        #模拟耗时操作
        def work(self):
            print "[%s] 模拟耗时网络IO, 等待3秒" % nowtime()
            time.sleep(3)
            self.d.callback('over')  # 因为是模拟的IO,任务完成后手动触发回调
    
        #处理成功回调
        def handle_success(self,d):
            print "[%s] 成功, 接收参数 = " % nowtime(), d
            a = [1, 2, 3][4]  # 这里会抛异常,添加到defered的errback链,然后由handle_error处理
        #处理异常回调
        def handle_error(self,d):
            print "[%s] 出错了" % nowtime(), repr(d)
    
    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()
        d = tester.getDefer() #拿到defered对象
        reactor.callWhenRunning(tester.work)#reactor调用耗时任务
        d.addCallback(tester.handle_success)
        d.addErrback(tester.handle_error)#defered对象添加处理的回调
        print "[%s] 启动reactor "%nowtime()
        reactor.callLater(5, stop) #5秒后停止reactor线程
        reactor.run()

    例子很简单,看下注释就清楚了,运行结果为

    [2018-10-25,16:10:38] 开始测试 
    [2018-10-25,16:10:38] 启动reactor 
    [2018-10-25,16:10:38] 模拟耗时网络IO, 等待3秒
    [2018-10-25,16:10:41] 成功, 接收参数 =  over
    [2018-10-25,16:10:41] 出错了 <twisted.python.failure.Failure exceptions.IndexError: list index out of range>
    [2018-10-25,16:10:43] 停止reactor

      有几点要注意下:

      1. 正常情况下,我们调用twisted的异步http client,会返回一个deferred对象,然后IO完成后,会自动触发deferred对象的事件,但我们这个例子只是简单的用time.sleep()模拟了下耗时操作,所以操作完成后,需要手动callback()去触发成功回调,实际编程中一般是不需要我们自己去触发的。

      2. deferred有两条回调链,分别是callback和errback,其中errback也非常重要,因为我们业务不可能次次都调用成功,添加异常处理是必需的!我们不需要再异步中去try except捕捉异常,只需要在上层调用中添加一个回调就可以,因为比如在N层回调中出现了异常,错误信息会记录在errback链中,在N-1层逻辑添加回调就可以了。

        如上面的例子,work操作完成后 ---> 触发handle_success回调,但是在handle_success里出现了错误,这个错误会自动以Failure对象记录到errback链中,我们只需要注册一个errback的处理逻辑就可以了,如handle_error,它接受的参数就是Failure对象。

      

  • 相关阅读:
    vmware虚拟机安装centos,配置PHP、mysql
    Java初学者不得不知的概念,JDK,JRE,JVM的区别?(转)
    char a[] = "hello world1"和char *p = "hello world2";的区别(转)
    关于二维数组传参做形参(转)
    最长连续字母序列的长度(阿里2015在线研发工程师笔试题)
    两个线程并发执行以下代码,假设a是全局变量,那么以下输出______是不可能的?
    软件工程
    面向对象基础
    eclipse
    设计模式(java)--状态模式
  • 原文地址:https://www.cnblogs.com/mactec/p/9850665.html
Copyright © 2011-2022 走看看