Python 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

我使用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 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的结果作为下一次回调的结果。我喜欢第二个想法,但我仍然需要与线程通信,以确定它是否打开,然后在队列中放置一些东西(如果是)。这并不能解决基本问题,即那些将阻止调用。无论如何,我实际上都在这样做,除了使用一个锁保护变量而不是队列。第一个想法可能确实有效,但我不确定这是否正是我想要的逻辑