扭曲:使代码无阻塞

acr*_*bia 19 python asynchronous twisted blocking

我对如何在python/twisted中编写异步代码感到有点困惑.假设(为了论证)我向世界公开一个函数,它接受一个数字并返回True/False,如果它是素数/非素数,所以它看起来像这样模糊:


def IsPrime(numberin):
    for n in range(2,numberin):
        if numberin % n == 0: return(False)
    return(True)
Run Code Online (Sandbox Code Playgroud)

(只是为了说明).

现在假设有一个网络服务器需要根据提交的值调用IsPrime.这需要很长时间才能完成numberin.

如果同时另一个用户请求一个小数的素数,有没有办法使用reactor/deferreds架构异步运行两个函数调用,以便在长计算结果之前返回短计算结果?

我知道如果IsPrime功能来自我的网络服务器将执行延迟的getPage的其他一些网络服务器,该怎么做呢,但如果它只是一个本地功能呢?

即,可以在两次调用IsPrime之间以某种方式进行Twisted时间共享,还是需要显式调用新线程?

或者,IsPrime循环是否需要分成一系列较小的循环,以便控制可以快速传递回反应堆?

或者是其他东西?

Jea*_*one 26

我认为你目前的理解基本上是正确的.Twisted只是一个Python库,你编写的Python代码正常执行,就像你期望的Python代码一样:如果你只有一个线程(和一个进程),那么一次只能发生一件事.Twisted提供的API几乎没有创建新的线程或进程,因此在正常情况下,您的代码会按顺序运行; isPrime在完成第一次执行之后才能再次执行.

仍然只考虑单个线程(和单个进程),Twisted的所有"并发"或"并行"来自这样一个事实:Twisted提供的工具不是阻塞网络I/O(以及某些其他阻塞操作).以非阻塞方式执行操作.这使得程序可以继续执行其他工作,否则可能无法等待阻塞I/O操作(例如读取或写入套接字)完成.

通过将它们分成小块并让事件处理程序在这些块之间运行,可以使事物"异步".如果转换不会使代码更难理解和维护,这有时是一种有用的方法.Twisted为调度这些工作块提供了帮助cooperate.使用此帮助程序是有益的,因为它可以根据所有不同的工作源做出调度决策,并确保在没有显着额外延迟的情况下有剩余时间来服务事件源(换句话说,您添加的作业越多) ,每个工作得到的时间越少,以便反应堆能够继续完成其工作).

Twisted还提供了几个用于处理线程和进程的API.如果不明显如何将作业分成块,这些可能很有用.您可以使用deferToThread在线程池中运行(线程安全!)函数.方便的是,此API返回一个Deferred最终将使用函数的返回值(或者Failure函数引发异常时)触发的API .这些延迟看起来像任何其他的,并且就使用它们的代码而言,它也可以从诸如getPage- 不使用额外线程的函数,只是非阻塞I/O和事件处理程序的调用中回来.

由于Python不适合在单个进程中运行多个CPU绑定线程,因此Twisted还提供了一个非阻塞API,用于启动子进程并与子进程通信.您可以将计算卸载到此类进程以利用额外的CPU或核心,而无需担心GIL会降低您的速度,这既不是分块策略也不是线程方法提供的.处理此类流程的最低级API是reactor.spawnProcess.还有安瓿,一个将为您管理过程池并deferToThread为过程提供模拟的软件包deferToAMPProcess.