使用扭曲矩阵的异步执行

async execution using twisted matrix

我正在尝试开发一个简单的扭曲矩阵示例,目的是执行函数的异步执行,但打印接缝告诉我执行是同步的还是按顺序执行的,我的误解在哪里?

from twisted.internet.defer import inlineCallbacks, returnValue
import time, random

def _print_(x):
    print "BAR", x

@inlineCallbacks
def sqrt(x):
    time.sleep(random.random())
    r = yield x*2
    print "FOO", r
    returnValue(r)

if __name__=='__main__':

    for dd in map(sqrt, range(10)):
        dd.addCallback(_print_)

Twisted 不会将阻塞代码转换为非阻塞代码,也不会将同步代码转换为异步代码。它为您提供了编写异步代码的工具。

inlineCallbacks 本质上与 Deferred 相同,但具有不同的 API。它不会改变 Twisted 的单线程、协作多任务处理特性。

您发布的程序按顺序对范围 (10) 中的整数调用 sqrt。每次调用 sqrt 都会随机休眠一段时间,然后计算结果。计算全部发生在单个线程中,因此一次只能发生一件事。当睡眠发生时,没有其他事情发生。

您可以做的是使用 Twisted 的助手之一来替换阻塞 time.sleep() 调用:

from twisted.internet.task import deferLater
from twisted.internet import reactor

@inlineCallbacks
def sqrt(x):
    yield deferLater(reactor, random.random(), lambda: None)
    r = yield x*2
    print "FOO", r
    returnValue(r)

现在 sqrt 不会阻塞 time.sleep() 调用。相反,它放弃了对反应堆的控制。 deferLater(...) returns 一个 Deferred 将在给定延迟后为您触发,并返回给定函数的结果(在这种情况下,该函数无关紧要,因为您只想睡觉,但是 deferLater需要一些函数)。

inlineCallbacks 相结合,这为您提供了 "sleep" 而不会 阻塞 反应器线程。随着时间的流逝,反应器可以自由地寻找其他事件来处理,直到 deferLater(...) Deferred 触发。发生这种情况时,可以在 sqrt 内恢复执行,并且可以继续计算。当然,请注意计算本身仍然是阻塞的。但是,由于它是一个简单的整数乘法,它可能不会阻塞足够长的时间。

deferLater 解决方案特定于 time.sleep。如果您有其他形式的阻塞,您可能需要了解其他 API 解决它们的方法。

您可能还想阅读 How do I add two integers together with Twisted?