Twisted学习(二)--------------构造Deferreds
来源:互联网 发布:海龟交易系统源码 编辑:程序博客网 时间:2024/05/29 12:54
构造Deferreds
Deferred对象是一种信号,当你调用一个函数而你想得到的数据还未返回时可以使用它。当一个函数返回了一个deferred对象,你可以为其关联一个函数用于处理数据返回。
这篇教程关注问题的另一半:如果写返回deferred对象的函数,也就是如何构造deferred对象,包括如何直接返回deferred对象而不阻塞代码执行,以及如何在数据可用时调用callbacks。
另外,这篇文档假设你对Twisted的异步编程模型比较熟悉,同时已经阅读过使用函数返回的deferred对象.
类概览
这是一个构造deferred对象和调用其callback或者errback的API参考。主并不意味着它是deferred类API的一个替代,只是提供一个如何使用的指引。
另外一篇关于如何使用函数返回deferred对象的文档,请参考使用函数返回的deferred对象.
基本的callback函数
callback(result)
用指定的结果运行callbacks. 只能调用一次. 多余的调用callback或者errback会导致twisted.internet.defer.AlreadyCalledError .如果在调用这这之后添加了callbacks或者errbacks,那么 addCallbacks 将会直接调用它们.
errback(failure)
用指定的failure运行errbacks. 只能调用一次. 多余的调用errback或者callback会导致twisted.internet.defer.AlreadyCalledError .如果在调用这这之后添加了callbacks或者errbacks,那么 addCallbacks 将会直接调用它们.
什么是Deferred不会做的:把你的代码转换为异步的
Deferred不会像变魔术似的把你的代码变成异步的,我们看下面的例子:
from twisted.internet import deferTARGET = 10000def largeFibonnaciNumber(): # create a Deferred object to return: d = defer.Deferred() # calculate the ten thousandth Fibonnaci number first = 0 second = 1 for i in xrange(TARGET - 1): new = first + second first = second second = new if i % 100 == 0: print("Progress: calculating the %dth Fibonnaci number" % i) # give the Deferred the answer to pass to the callbacks: d.callback(second) # return the Deferred with the answer: return dimport timetimeBefore = time.time()# call the function and get our Deferredd = largeFibonnaciNumber()timeAfter = time.time()print("Total time taken for largeFibonnaciNumber call: %0.3f seconds" % \ (timeAfter - timeBefore))# add a callback to it to print the numberdef printNumber(number): print("The %dth Fibonacci number is %d" % (TARGET, number))print("Adding the callback now.")d.addCallback(printNumber)
你会注意到尽管在largeFibonnaciNumber函数中创建了deferred对象,发生了下面的事情:
- "Total time taken for largeFibonnaciNumber call"输出意味着函数并没有直接返回并以我们期望的异步方式来运行。
- callback并没有在结果返回前添加到deferred对象中,也没有在结果返回时调用,甚至在计算完成之后它也没有添加到deferred对象中。
函数在返回之前已经完成了计算,计算阻塞了当前进程直到完成,这是异步代码不会做的。Deferred不是非阻塞代码的法宝:它们是异步函数用来传递结果给callbacks的信号,但是使用Deferred不保证你得到一个异步函数。
高级进程链控制
pause()
停止调用添加进来的方法,然后不响应callback,直接到调用unpase()calling any methods as they are added, and do notrespond to
callback
, untilself.unpause()
is called.unpause()
如果这个deferred对象上的callback已经在运行,则会调用所有添加到此Deferred对象上的callbacks尽管已经调用了pause。
这会将Deferred 置于一个状态,在这个状态下o
addCallbacks
或者callback
将会正常工作.
从同步函数中返回Deferreds
有时候你希望在同步函数中返回一个deferred.有以下几个原因:
- 需要与其它返回deferred对象版本的API兼容
- 将来你的代码可能变为异步的
在使用函数返回的deferred对象中,我们给出了以下同步代码:
def synchronousIsValidUser(user): ''' Return true if user is a valid user, false otherwise ''' return user in ["Alice", "Angus", "Agnes"]
尽管我们可以要求调用我们函数的代码用maybeDeferred包装同步结果,但是出于API兼容考虑,我们最好自己使用defer.succeed来返回一个deferred对象。
from twisted.internet import deferdef immediateIsValidUser(user): ''' Returns a Deferred resulting in true if user is a valid user, false otherwise ''' result = user in ["Alice", "Angus", "Agnes"] # return a Deferred object already called back with the value of result return defer.succeed(result)
有一个等价的defer.fail方法来返回一个errback链已经开始执行的deferred.
用Twisted来集成阻塞代码
在一些情况下,你可能需要调用阻塞代码: 许多第三方库的函数都有需要长时间运行的需要阻塞函数.没有办法强制一个函数变为异步的: 它必须用特定的方式来编写. 当使用Twisted时,你自己的代码需要是异步的, 但是对于第三库,你没有办法重写它们来保证异步.
对于这种情况,Twisted提供了在独立线程中运行阻塞代码而不阻塞我们程序的方法.twisted.internet.threads.deferToThread 将会使用一个线程来运行我们的阻塞代码,返回一个deferred对象并在线程完成时执行callback.
现在我们假设largeFibonnaciNumber
函数是第三方的一个库函数 (返回计算结果而不是deferred对象)要修改它,使它在不同一进程中运行完成而不阻塞是不容易的. 下面的例子展示了在一个线程中运行它, 和前面提到这个程序时不同的是它不会阻塞我们的程序:
def largeFibonnaciNumber(): """ Represent a long running blocking function by calculating the TARGETth Fibonnaci number """ TARGET = 10000 first = 0 second = 1 for i in xrange(TARGET - 1): new = first + second first = second second = new return secondfrom twisted.internet import threads, reactordef fibonacciCallback(result): """ Callback which manages the largeFibonnaciNumber result by printing it out """ print("largeFibonnaciNumber result =", result) # make sure the reactor stops after the callback chain finishes, # just so that this example terminates reactor.stop()def run(): """ Run a series of operations, deferring the largeFibonnaciNumber operation to a thread and performing some other operations after adding the callback """ # get our Deferred which will be called with the largeFibonnaciNumber result d = threads.deferToThread(largeFibonnaciNumber) # add our callback to print it out d.addCallback(fibonacciCallback) print("1st line after the addition of the callback") print("2nd line after the addition of the callback")if __name__ == '__main__': run() reactor.run()
可能的代码错误
通过提供标准注册callbacks的方式,Deferreds大大简化了编写异步代码的过程。但是使用它们,你可能需要遵循一些微妙甚至困惑的规则。这更多时候是对那些在新系统内部构造并编写Deferreds的人们,而不是那些使用其它系统返回的deferreds对象并在上面添加callbacks的人们。然而,你最好知道这些。
不可能多次执行deferred
Deferred只能执行一次,你只能调用callback或者errback一次。当你添加新的callbacks时,进程链会继续在已经执行的deferred上运行。
同步执行callback
如果一个deferred对象已经有了结果,addcallback可能会直接同步调用callback:也就是说,在它添加之后直接调用。在callback需要修改状态的场合,你可能希望执行链挂起直到所有的callbacks都添加完成。这时你可以使用pause和unpause来控制执行链。
当你使用这些方法时要小心,如果你pause了deferred,你有责任unpause它。添加callbacks的函数必须unpause已经pause的deferred,这不应该是实际上调用callback或者errback执行deferred的代码的责任,因为这会使它们没有作用。
- Twisted学习(二)--------------构造Deferreds
- twisted python 学习笔记:二
- twisted学习笔记之二: 延迟对象deferred
- twisted学习笔记之二: 延迟对象deferred
- python的twisted 学习
- twisted学习之一
- twisted学习摘要
- Python Twisted学习总结
- twisted学习笔记
- twisted学习笔记
- Twisted 学习1
- Twisted学习记录
- Twisted之Deferred(二)
- Twisted 学习乱记1
- twisted的学习资料【转】
- twisted python学习笔记:一
- twisted python学习笔记:三
- Twisted学习(一)----------------------Deffered参考
- 人脸识别引擎SeetaFaceEngine简介及在windows7 vs2013下的编译
- 调整数组顺序使奇数位于偶数前面
- zabbix从2.6到3.0 脚本参数设置的变化
- Linux C——select函数详解及其应用
- 文件操作
- Twisted学习(二)--------------构造Deferreds
- 计算点云的最小BBOX
- 《Android 群英传》读书笔记:自定义 View 之创建复合控件
- 形参与实参
- FATAL ERROR: MarkCompactCollector: semi-space copy, fallback in old gen Allocation failed - JavaScri
- 笔记
- ubuntu基本配置
- 超级楼梯
- 找到关键点web,js