Python twisted:如何在反应器代码和线程代码之间优雅地通信?
我使用twisted将客户机连接到服务器。客户端有一个线程,该线程可能正在后台执行操作。当反应堆关闭时,我必须:Python twisted:如何在反应器代码和线程代码之间优雅地通信?,python,multithreading,twisted,shutdown,Python,Multithreading,Twisted,Shutdown,我使用twisted将客户机连接到服务器。客户端有一个线程,该线程可能正在后台执行操作。当反应堆关闭时,我必须: 1) check if the thread is doing things 2) stop it if it is 这样做的优雅方式是什么?我所能做的就是做一些困惑的事情,比如: def cleanup(self): isWorkingDF = defer.Deferred() doneDF = defer.Deferred() def checkIsW
1) check if the thread is doing things
2) stop it if it is
这样做的优雅方式是什么?我所能做的就是做一些困惑的事情,比如:
def cleanup(self):
isWorkingDF = defer.Deferred()
doneDF = defer.Deferred()
def checkIsWorking():
res = self.stuff.isWorking() #blocking call
reactor.callFromThread(isWorkingDF.callback, res)
def shutdownOrNot(isWorking):
if isWorking:
#shutdown necessary, shutdown is also a blocking call
def shutdown():
self.stuff.shutdown()
reactor.callFromThread(doneDF, None)
reactor.callInThread(shutdown)
else:
doneDF.callback(None) #no shutdown needed
isWorkingDF.addCallback(shutdownOrNot)
reactor.callInThread(checkIsWorking)
return doneDF
首先我们检查它是否工作正常。回调的结果进入rescallback
,它要么关闭,要么不关闭,然后触发doneDF,twisted将等待直到关闭
真是一团糟啊!有更好的办法吗
也许一个相关的问题是,是否有一种更优雅的方式将回调链接到彼此?我可以看到我自己在完成后需要做更多的清理代码,所以我必须做一个不同的
done
deferred,并让当前的doneDF
启动一个回调,该回调做一些事情,然后调用done
deferred..如果程序在关闭反应器后终止,则可以使线程成为守护进程线程。这将在所有非守护进程线程终止时自动退出。在调用start()之前,只需在thread对象上设置daemon=True
如果这是不可行的,例如线程必须在退出之前进行资源清理,那么您可以使用队列在反应器和线程之间进行通信。将要完成的工作推到队列对象上,让线程将其拔出并执行。有一个特殊的“FINISH”标记(或者干脆没有)来指示线程需要终止。您可以通过使用
deferToThread
而不是callInThread
/callFromThread
对来简化此过程:
from twisted.internet.threads import deferToThread
def cleanup(self):
isWorkingDF = deferToThread(self.stuff.isWorking)
def shutdownOrNot(isWorking):
if isWorking:
#shutdown necessary, shutdown is also a blocking call
return deferToThread(self.stuff.shutdown)
isWorkingDF.addCallback(shutdownOrNot)
return isWorkingDF
deferToThread
基本上只是一个很好的包装器,它与您在函数版本中两次实现的线程逻辑相同。啊,真正的答案是使用defer.inlineCallbacks
装饰器。上述代码现在变为:
@defer.inlineCallbacks
def procShutdownStuff(self):
isWorking = yield deferToThread(self.stuff.isWorking)
if isWorking:
yield deferToThread(self.stuff.shutdown)
def cleanup(self):
return self.procShutdownStuff()
啊,这可能就是我想要的,是的。我认为您在这里也添加了另一个元素-如果您从另一个deferred调用的回调返回deferred,会发生什么?我不认为deferred也会被等待,但也许我错了?我仍然需要更多的延迟,但是defertothread使代码变得更好。如果从另一个延迟(y)上的回调返回一个延迟(x),那么y将暂停处理其回调链,直到x得到结果。然后y将继续使用x的结果作为下一次回调的结果。我喜欢第二个想法,但我仍然需要与线程通信,以确定它是否打开,然后在队列中放置一些东西(如果是)。这并不能解决基本问题,即那些将阻止调用。无论如何,我实际上都在这样做,除了使用一个锁保护变量而不是队列。第一个想法可能确实有效,但我不确定这是否正是我想要的逻辑