[英]Correct use of API with threading in daemonized twisted
I'm using a service whose API uses threading.Thread and I want to use Deferreds inside it. 我正在使用API使用threading.Thread的服务,并且想在其中使用Deferreds。
If I run it like a standard python module I don't have any problem. 如果我像标准的python模块一样运行它,我没有任何问题。 Something like:
就像是:
from twisted.internet import reactor
from outside import ServiceUsingThreadingAndDeferred
service = ServiceUsingThreadingAndDeferred()
reactor.listenTCP(port, protocol_factory)
service.start()
reactor.run()
While if I run the following .tac with twistd -y the service is simply not working: 如果我使用twisted -y运行以下.tac,则该服务将无法正常工作:
from twisted.application import internet, service
from outside import ServiceUsingThreadingAndDeferred
service = ServiceUsingThreadingAndDeferred()
# Application set-up
application = service.Application("appName")
my_server = internet.TCPServer(port, protocol_factory)
my_server.setServiceParent(application)
service.start()
I think the problem in the second case is that the main reactor thread is not spawning the service threads itself, but then I don't see why (and if) it happens in the first case... I used callLater as a workaround -successfully: 我认为第二种情况的问题是主反应堆线程没有生成服务线程本身,但是我不明白为什么(如果有)在第一种情况下发生……我使用callLater作为解决方法-成功地:
from twisted.application import internet, service
from outside import ServiceUsingThreadingAndDeferred
from twisted.internet import reactor
service = ServiceUsingThreadingAndDeferred()
# Application set-up
application = service.Application("appName")
my_server = internet.TCPServer(port, protocol_factory)
my_server.setServiceParent(application)
reactor.callLater(1, service.start)
but I don't know if it's the correct way to tackle this. 但我不知道这是否是解决此问题的正确方法。 Do you have any advice?
您有什么建议吗?
From the Github repo, this class misuses Twisted's threading API: 在Github存储库中,此类滥用Twisted的线程API:
class ServiceUsingThreadingAndDeferred():
def __init__(self):
pass
def start(self):
print "3rd party API service starting..."
self.run_as_thread()
def run_as_thread(self, *args, **kwargs):
t = threading.Thread(target=self.run_forever, args=args, kwargs=kwargs)
t.daemon = True
t.start()
def run_forever(self):
while 1:
print "Doing something remote..."
time.sleep(1)
now = time.time()
if 1 > now % 5 >= 0:
self.defer_activity()
def defer_activity(self):
threads.deferToThread(self._activity)
ServiceUsingThreadingAndDeferred.run_forever
runs in a non-reactor thread. ServiceUsingThreadingAndDeferred.run_forever
在非反应器线程中运行。 It calls defer_activity
which calls threads.deferToThread
. 它调用
defer_activity
这就要求threads.deferToThread
。 It is not allowed to call threads.deferToThread
in a non-reactor thread. 不允许在非反应堆线程中调用
threads.deferToThread
。 There is approximately one Twisted API that it is safe to call in a non-reactor thread: reactor.callFromThread
(it schedules a call to its argument to run in the reactor thread). 可以安全地在非反应堆线程中调用的Twisted API大约为:
reactor.callFromThread
(它调度对其参数的调用以在反应堆线程中运行)。
working.tac
does the same thing but gets lucky and so appears to work on some versions of Twisted. working.tac
做同样的事情,但是很幸运,因此似乎可以在某些版本的Twisted上使用。 It is relying on undefined behavior that results from calling threads.deferToThread
in a non-reactor thread interacting with how callLater
is implemented. 它依赖于非反应器线程中调用
threads.deferToThread
导致的未定义行为,该非反应器线程与如何实现callLater
交互。 There's no guarantee it works completely or that the behavior is portable across Twisted versions or platforms. 无法保证它可以完全正常运行,也不能保证行为可以在Twisted版本或平台之间移植。
If you want to use the reactor's threadpool from a non-reactor thread, you need to write something like: 如果要从非反应堆线程中使用反应堆的线程池,则需要编写如下内容:
from twisted.internet.threads import (
blockingCallFromThread,
deferToThread,
)
d = blockingCallFromThread(reactor, lambda: deferToThread(self._activity))
However, you may not use any methods of d
(the Deferred
returned by deferToThread
) in a non-reactor thread, either. 但是,您可能无法使用的任何方法
d
(在Deferred
通过返回deferToThread
在非反应堆线程),无论是。
Most likely, if at all possible, you should rewrite the logic of ServiceUsingThreadingAndDeferred
so that it is compatible with the reactor and then you can avoid all of these shennanigans. 很可能(如果有可能),您应该重写
ServiceUsingThreadingAndDeferred
的逻辑,以便它与反应堆兼容,然后可以避免所有这些问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.