Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python twisted:在同步代码中处理传入事件_Python_Event Handling_Twisted - Fatal编程技术网

Python twisted:在同步代码中处理传入事件

Python twisted:在同步代码中处理传入事件,python,event-handling,twisted,Python,Event Handling,Twisted,假设在一个twisted支持的Python程序中有一个同步函数,它需要很长时间才能执行,这需要大量大小合理的工作。如果函数可以返回延迟,这将是一个不需要动脑筋的问题,但是函数恰好位于某些同步代码的深处,因此不可能让延迟继续 有没有一种方法可以让twisted在不离开该功能的情况下处理未完成的事件?也就是说,我想做的事情是 def my_func(): 结果=[] 对于一个或多个或多个项目()中的项目: 结果.追加(do_计算(项目)) 反应器。处理未完成的事件() 返回结果 当然,这对代码提出

假设在一个twisted支持的Python程序中有一个同步函数,它需要很长时间才能执行,这需要大量大小合理的工作。如果函数可以返回延迟,这将是一个不需要动脑筋的问题,但是函数恰好位于某些同步代码的深处,因此不可能让延迟继续

有没有一种方法可以让twisted在不离开该功能的情况下处理未完成的事件?也就是说,我想做的事情是

def my_func():
结果=[]
对于一个或多个或多个项目()中的项目:
结果.追加(do_计算(项目))
反应器。处理未完成的事件()
返回结果

当然,这对代码提出了可重入性要求,但Qt中仍然有这样的要求,twisted中有什么吗?

您可以使用deferToThread

该方法在单独的线程中运行您的计算,并返回一个延迟值,该值在计算实际完成时被回调。

这应该可以:

for item in items:
    reactor.callLater(0, heavy_func, item)

reactor.callLater应该将您带回事件循环

问题是如果
do\u heavy\u computation()
是阻塞的代码,那么执行将不会转到下一个函数。在这种情况下,使用
deletothread
blockingCallFromThread
进行繁重的计算。此外,如果您不关心计算结果,则可以使用
callInThread
。看看

一些基于事件循环的系统采用的解决方案(基本上就是您通过Qt的
QCoreApplication.processEvents
API引用的解决方案)是使主循环重新进入。在扭曲的术语中,这意味着类似(工作代码):

注意有两个
反应器。在这个程序中运行
调用。如果Twisted有一个可重入事件循环,那么第二次调用将再次开始旋转反应器,直到遇到匹配的
反应器.stop
调用后才会返回。反应器将处理它所知道的所有事件,而不仅仅是由
dou_work
生成的事件,因此你将拥有你想要的行为

这需要一个可重入事件循环,因为反应器循环已经在调用
my\u-expensive\u-task…
。reactor循环位于调用堆栈上。然后,
reactor.run
被调用,此时reactor循环再次位于调用堆栈上。因此,通常的问题是:事件循环不能在其框架中保留状态(否则,在嵌套调用完成时它可能无效),在调用其他代码时,它不能使其实例状态不一致,等等

Twisted没有可重入事件循环。这是一个已经被考虑过的特性,至少在过去被明确拒绝了。支持这些特性会给实现和应用程序带来大量额外的复杂性(如上所述)。如果事件循环是可重入的,那么就很难避免要求所有应用程序代码也是可重入安全的。这否定了Twisted对并发性的协作多任务方法的一个主要好处(即保证您的函数不会被重新输入)

因此,当使用Twisted时,此解决方案已过时

我不知道还有另一种解决方案允许您继续在reactor线程中运行此代码。您提到,所讨论的代码深入嵌套在其他一些同步代码中。想到的其他选项有:

  • 使同步代码能够处理异步事务
  • 首先计算出昂贵的部分,然后将结果传递给代码的其余部分
  • 在另一个线程中运行所有这些代码,而不仅仅是计算代价高昂的部分

如果我可以将
my_func
的结果作为延迟返回,那会有所帮助,但正如我所说的,它深深地隐藏在同步代码中,要返回延迟,我必须重写它,将延迟的结果一直带到事件循环中。我已经更新了问题,以反映单个迭代时间是可以的,相反,整个迭代时间太长了。好吧,我知道我可能会把人们和“重”部分混淆了。处理一个项目是好的,当有很多项目时,延迟真的开始生效。让我稍微修改一下这个问题。
def my_expensive_task_that_cannot_be_asynchronous():
    @inlineCallbacks
    def do_work(units):
        for unit in units:
            yield do_one_work_asynchronously(unit)
    work = do_work(some_work_units())
    work.addBoth(lambda ignored: reactor.stop())
    reactor.run()

def main():
    # Whatever your setup is...
    # Then, hypothetical event source triggering your
    # expensive function:
    reactor.callLater(
        30,
        my_expensive_task_that_cannot_be_asynchronous,
    )
    reactor.run()