简体   繁体   English

正确使用守护进程扭曲的线程中的API

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM