假设我们有一个 blackbox 生成器,它完全阻塞并永远运行。我们正在运行Twisted,因此处理阻止内容的标准方法是使用Formatters
或defers
。
defers + threads
耶!工作完成了! ......但不完全是。
在我们想要停止整个Twisted应用程序之前,一切都很棒。其中一个关闭步骤是调用类似〜# some very naive example
from twisted.internet import reactor
def aSillyBlockingMethod():
for results in fullblocking_blockbox_generator_that_runs_forever():
print results
reactor.callInThread(aSillyBlockingMethod)
reactor.run()
的东西,它等待所有线程完成自己。但不是我们的完整的以太网 blackbox 生成器。我们不能在循环中做很多事情,因为我们需要从发生器中得到永远不会发生的结果。
我浏览整个互联网的想法。没有。也许我错过了一些重要的事情,或者有一种聪明的方法可以解决这个问题?
答案 0 :(得分:0)
我接受了this post提供的答案并添加了示例代码。另外请记住,最好为线程定义明确的起点和终点。正如您所看到的,如果线程以不受控制的方式永远运行,它可能会导致一些非常棘手的情况。话虽如此,有时某些情况是不可避免的(但这并不意味着我们不应该尽可能避免它。)
如果 blackbox 不需要Twisted中的任何内容,您可以将其作为Twisted控件之外的守护程序线程启动,该程序将在您的应用程序停止时停止。一般来说,这是非常危险,因为这会立即杀死线程,这可能会使事情处于损坏状态。无论如何,这是一个例子:
from threading import Thread, Event
from time import sleep
from twisted.internet import reactor
class BlackBox(Thread):
def __init__(self, stop_event=None):
super(BlackBox, self).__init__()
if not stop_event:
stop_event = Event()
self.stop_event = stop_event
def run(self):
while True:
print('running in thread')
if self.stop_event.is_set():
print('STOPPING!')
break
sleep(1)
t = BlackBox()
t.daemon = True
t.start()
# reactor.callLater(5, t.stop_event.set) # if you want to stop thread after 5 seconds
reactor.run()
更好的选项是在线程代码中有一个控制流,例如检查Event
,并在应用关闭时启动触发器。要在Twisted中捕获此类触发器,请使用reactor.addSystemEventTrigger
。
from threading import Event
from time import sleep
from twisted.internet import reactor
def aSillyBlockingMethod(event):
while True:
print('running in thread')
if event.is_set():
print('STOPPING')
break
sleep(1)
stop_event = Event()
reactor.callInThread(aSillyBlockingMethod, stop_event)
reactor.addSystemEventTrigger('before', 'shutdown', stop_event.set)
reactor.run()
选项#2是比守护程序线程更好的解决方案,因为线程代码不会随意停止,您可以让Twisted管理线程,并且线程可以在适当的时间停止(由开发人员认为)。我希望这有帮助