正确使用API​​与daemonized twisted中的线程

时间:2017-11-03 16:14:48

标签: twisted python-multithreading twistd

我正在使用其API使用threading.Thread的服务,我想在其中使用Deferred。

如果我像标准的python模块一样运行它,我没有任何问题。类似的东西:

from twisted.internet import reactor
from outside import ServiceUsingThreadingAndDeferred

service = ServiceUsingThreadingAndDeferred()

reactor.listenTCP(port, protocol_factory)

service.start()

reactor.run()

如果我使用 twistd -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()

我认为第二种情况下的问题是主反应堆线程本身并没有产生服务线程,但是我不知道为什么(如果)它发生在第一种情况......我使用过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)

但我不知道这是否是解决这个问题的正确方法。你有什么建议吗?

1 个答案:

答案 0 :(得分:0)

从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在非反应堆线程中运行。它会调用defer_activity来调用threads.deferToThread。不允许在非反应器线程中调用threads.deferToThread。在非反应器线程中可以安全地调用大约一个Twisted API:reactor.callFromThread(它调度对其参数的调用以在反应器线程中运行)。

working.tac做同样的事情,但很幸运,因此似乎适用于某些版本的Twisted。它依赖于在非反应器线程中调用threads.deferToThread与实现callLater的方式交互而导致的未定义行为。并不能保证它完全可以正常工作,或者这种行为可以在Twisted版本或平台上移植。

如果你想使用来自非反应堆线程的反应堆线程池,你需要编写如下内容:

from twisted.internet.threads import (
    blockingCallFromThread,
    deferToThread,
)

d = blockingCallFromThread(reactor, lambda: deferToThread(self._activity))

但是,您也不能在非反应堆线程中使用dDeferred返回的deferToThread)的任何方法。

最有可能的是,如果可能的话,你应该重写ServiceUsingThreadingAndDeferred的逻辑,以便它与反应堆兼容,然后你就可以避免所有这些shennanigans。