在Twisted中使用线程
在Twisted中使用线程
译者: | gashero |
---|
1 以线程安全的模式运行代码
Twisted中的大部分代码都不是线程安全的。例如protocol向transport写入数据就不是线程安全的。因此我们需要一种方法来在主事件循环中进行调度。者可以使用函数 twisted.internet.interfaces.IReactorThreads.callFromThread 来实现:
from twisted.internet import reactor def notThreadSafe(x): """做一些非线程安全的事情""" # ... def threadSafeScheduler(): """以线程安全方式运行""" reactor.callFromThread(notThreadSafe,3) #将会运行notThreadSafe(3)在主时间循环中
Note
译者注
callFromThread 意指从线程调用,这个方法是供线程调用的,并且使其指定的函数加入到主事件循环中执行。比如worker线程可以调用此方法将提交结果的函数加入到主事件循环中。这样就可以确保多线程的运行worker,而有可以使用线程安全的方式提交结果。
2 在线程中运行代码
有时我们希望在线程中运行代码,比如阻塞的存取API。Twisted提供了这样做的方法在 IReactorThread API 中。附加的工具在包 twisted.internet.threads 中提供。这些方法允许我们把任务排队以后在线程池中运行。
例如,在线程中运行一个函数,我们可以:
from twisted.internet import reactor def aSillyBlockingMethod(x): import time time.sleep(2) print x # 在线程中运行 reactor.callInThread(aSillyBlockingMethod,"2 secodns have passed")
Note
译者注
callInThread 意指在线程中运行,调用该方法需要在主事件循环中,而执行其传入的函数则是在线程中。可以与上一节提供的 callFromThread`结合使用,即在worker线程函数中调用 `callFromThread 提交结果。
3 工具函数
工具函数作为 twisted.internet.reactor 的一部分API提供,但是并不是在 twisted.internet.threads 中实现的。
如果我们有多个方法需要在线程中以队列方式运行,我们可以做:
from twisted.internet import threads def aSillyBlockingMethodOne(x): import time time.sleep(2) print x def aSillyBlockingMethodTwo(x): print x # 排队后在线程中运行两个方法 commands=[(aSillyBlockingMethodOne,["calling first"])] commands.append((aSillyBlockingMethodTwo,["and the second"],{})) threads.callMultipleInThread(commands)
如果我们希望得到函数的运行结果,那么我们可以使用Deferred:
from twisted.internet import threads def doLongCalculation(): # ... do long calculation here ... return 3 def printResult(x): print x # 在线程中运行,并且通过 defer.Deferred 获取结果 d=threads.deferToThread(doLongCalculation) d.addCallback(printResult)
如果你希望在reactor线程中调用一个方法,并且获取结果,你可以使用 blockingCallFromThread
from twisted.internet import threads,reactor,defer from twisted.web.client import getPage from twisted.web.error import Error def inThread(): try: result=threads.blockingCallFromThread(reactor,getPage,"http://twistedmatrix.com/") except Error,exc: print exc else: print result reactor.callFromThread(reactor.stop) reactor.callInThread(inThread) reactor.run()
blockingCallFromThread 将会返回对象或者抛出异常,或者通过抛出到传递给他的函数。如果传递给它的函数返回了一个Deferred,他会返回Deferred回调的值或者抛出异常到errback。
4 管理线程池
线程池是在 twisted.python.threadpool.ThreadPool 中实现的。
我们可以修改线程池的大小,增加或者减少可用线程的数量,可以这么做:
from twisted.internet import reactor reactor.suggestThreadPoolSize(30)
缺省的线程池大小依赖于使用的reactor,缺省的reactor使用最小为5个,最大为10个。在你改变线程池尺寸之前,确保你理解了线程和他们的资源使用方式。
在Twisted2.5.0中使用线程
译者: | gashero |
---|
刚才翻译了对应版本8.0.0的Twisted的线程指南,但是我还是在用2.5.0,所以这里只记录与8.0.0的差异,不做重新翻译。
当你开始使用线程之前,确保你在启动程序的时候使用了如下:
from twisted.python import threadable threadable.init()
这回让Twisted以线程安全的方式初始化,不过仍然注意,Twisted的大部分仍然不是线程安全的。
以线程安全的方式运行代码中初始化多了两行:
from twisted.python import threadable threadable.init(1)
2.5.0的文档中没有 blockingCallFromThread 的例子。也许根本就没有这个方法。
实际我下载文档的版本是2.4.0,不过应该与2.5.0一样的。