Skip to main content
 首页 » 编程设计

python之使用 Twisted 和 PB 等待事件

2025年05月04日13mq0036

我有一个使用多线程的 python 应用程序,我很好奇在 python 中等待某些东西而不燃烧 cpu 或锁定 GIL 的最佳方法。

我的应用程序使用 twisted,我生成一个线程来运行长时间的操作,这样我就不会踩到 reactor 线程。这个长操作还会使用 twisted 的 deferToThread 生成一些线程来做其他事情,而原始线程想要等待 defereds 的结果。

我一直在做的是这个

while self._waiting: 
    time.sleep( 0.01 ) 

这似乎扰乱了扭曲的 PB 对象接收消息,所以我认为 sleep 锁定了 GIL。以下发帖人的进一步调查显示,事实并非如此。

有更好的方法可以在不阻塞 react 器线程或下面发布的 python 的情况下等待线程。

请您参考如下方法:

如果您已经在使用 Twisted,您永远不需要像这样“等待”。

正如您所描述的那样:

I spawn a thread to run a long operation ... This long operation also spawns some threads using twisted's deferToThread ...

这意味着您是从“长操作”线程调用 deferToThread,而不是从主线程(运行 reactor.run() 的线程)调用.正如 Jean-Paul Calderone 已经在评论中指出的那样,您可以仅从主 react 器线程调用 Twisted API(例如 deferToThread)。

您看到的锁定是不遵守此规则的常见症状。它与 GIL 无关,而与您将 Twisted 的 react 器置于损坏状态这一事实有关。

根据您对程序的松散描述,我尝试编写一个示例程序来完全基于 Twisted API 执行您正在谈论的内容,通过 Twisted 生成所有线程并从主 react 器线程控制它们。

import time 
 
from twisted.internet import reactor 
from twisted.internet.defer import gatherResults 
from twisted.internet.threads import deferToThread, blockingCallFromThread 
 
def workReallyHard(): 
    "'Work' function, invoked in a thread." 
    time.sleep(0.2) 
 
def longOperation(): 
    for x in range(10): 
        workReallyHard() 
        blockingCallFromThread(reactor, startShortOperation, x) 
    result = blockingCallFromThread(reactor, gatherResults, shortOperations) 
    return 'hooray', result 
 
def shortOperation(value): 
    workReallyHard() 
    return value * 100 
 
shortOperations = [] 
 
def startShortOperation(value): 
    def done(result): 
        print 'Short operation complete!', result 
        return result 
    shortOperations.append( 
        deferToThread(shortOperation, value).addCallback(done)) 
 
d = deferToThread(longOperation) 
def allDone(result): 
    print 'Long operation complete!', result 
    reactor.stop() 
d.addCallback(allDone) 
 
reactor.run() 

请注意,在 allDone 中 react 器停止的位置,您可以启动另一个“长操作”并让它重新开始整个过程​​。