有多处理工作者的扭曲网络客户端?

时间:2009-09-24 10:28:19

标签: python twisted multiprocessing

所以,我有一个使用Twisted + Stomper作为STOMP客户端的应用程序,它将工作分配给多处理工具.Pool of workers。

当我只使用python脚本启动时,这似乎工作正常,(简化)看起来像这样:

# stompclient.py

logging.config.fileConfig(config_path)
logger = logging.getLogger(__name__)

# Add observer to make Twisted log via python
twisted.python.log.PythonLoggingObserver().start() 

# initialize the process pool.  (child processes get forked off immediately)
pool = multiprocessing.Pool(processes=processes)

StompClientFactory.username = username
StompClientFactory.password = password
StompClientFactory.destination = destination
reactor.connectTCP(host, port, StompClientFactory())
reactor.run()

当这个打包进行部署时,我想我会利用扭曲的脚本并从tac文件中运行它。

这是我非常相似的tac文件:

# stompclient.tac

logging.config.fileConfig(config_path)
logger = logging.getLogger(__name__)

# Add observer to make Twisted log via python
twisted.python.log.PythonLoggingObserver().start() 

# initialize the process pool.  (child processes get forked off immediately)
pool = multiprocessing.Pool(processes=processes)

StompClientFactory.username = username
StompClientFactory.password = password
StompClientFactory.destination = destination

application = service.Application('myapp')

service = internet.TCPClient(host, port, StompClientFactory())
service.setServiceParent(application)

为了便于说明,我已经崩溃或改变了一些细节;希望它们不是问题的本质。例如,我的应用程序有一个插件系统,池由一个单独的方法初始化,然后使用pool.apply_async()传递我的插件的process()方法之一,将工作委托给池。

因此,如果我运行脚本(stompclient.py),一切都按预期工作。

如果我在非守护进程模式(-n)中运行扭曲,它似乎也可以正常工作:

twistd -noy stompclient.tac

但是,当我以守护进程模式运行时,它工作:

twistd -oy stompclient.tac

应用程序似乎启动正常,但是当它试图分叉工作时,它就会挂起。通过“挂起”,我的意思是看起来子进程从未被要求做任何事情,而父进程(称为pool.apply_async())只是坐在那里等待响应返回。

我确信我正在使用Twisted +多处理做一些愚蠢的事情,但我真的希望有人可以解释我的方法中的缺陷。

提前致谢!

2 个答案:

答案 0 :(得分:12)

由于您的工作调用和非工作调用之间的差异只是“-n”选项,因此问题很可能是由守护进程(“-n”阻止发生)引起的。< / p>

在POSIX上,守护进程中涉及的步骤之一是分叉并具有父出口。其中之一是,您的代码运行的过程与评估.tac文件的过程不同。这也重新安排了在.tac文件中启动的进程的子/父关系 - 作为您的多处理进程池。

多处理池的进程从您启动的扭曲进程的父进程开始。但是,当该进程作为守护进程的一部分退出时,它们的父进程将成为系统初始化进程。这可能会导致一些问题,尽管可能不是您描述的悬而未决的问题。可能还有其他类似的低级实现细节,通常允许多处理模块工作,但是由守护进程中断。

幸运的是,避免这种奇怪的互动应该是直截了当的。 Twisted的服务API允许您在守护程序完成后运行代码。如果您使用这些API,那么您可以延迟多处理模块的进程池的初始化,直到守护进程,并希望避免该问题。以下是可能的示例:

from twisted.application.service import Service

class MultiprocessingService(Service):
    def startService(self):
        self.pool = multiprocessing.Pool(processes=processes)

MultiprocessingService().setServiceParent(application)

现在,另外,您可能还会遇到与清理多处理模块的子进程有关的问题,或者可能与使用Twisted的进程创建API,reactor.spawnProcess创建的进程有关的问题。这是因为正确处理子进程的一部分通常涉及处理SIGCHLD信号。但是,扭曲和多处理在这方面不会合作,因此其中一个将会收到所有孩子退出的通知,而另一个将永远不会得到通知。如果您根本不使用Twisted的API来创建子进程,那么这对您来说可能没问题 - 但您可能需要检查以确保多处理模块尝试安装的任何信号处理程序实际上“获胜”并且不会获得由Twisted自己的处理程序取代。

答案 1 :(得分:0)

可能的想法......

在守护进程模式下运行时,twistd将关闭stdin,stdout和stderr。您的客户是否会读取或写入这些内容?