7

そのため、Twisted + Stomper を STOMP クライアントとして使用するアプリケーションを用意しました。これは、作業を multiprocessing.Pool のワーカーにファームアウトします。

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()

これは展開用にパッケージ化されるので、twistd スクリプトを利用して 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)

説明のために、いくつかの詳細を折りたたんだり変更したりしています。うまくいけば、それらは問題の本質ではありませんでした。たとえば、私のアプリにはプラグイン システムがあり、プールは別のメソッドによって初期化され、その後、プラグインの process() メソッドの 1 つを渡す pool.apply_async() を使用して、作業がプールに委任されます。

したがって、スクリプト (stompclient.py) を実行すると、すべてが期待どおりに機能します。

非デーモン モード (-n) で twist を実行しても、問題なく動作するように見えます。

twistd -noy stompclient.tac

ただし、デーモン モードで実行すると機能しません。

twistd -oy stompclient.tac

アプリケーションは正常に起動しているように見えますが、作業をフォークしようとするとハングします。「ハング」とは、子プロセスが何も要求されず、親 (pool.apply_async() と呼ばれる) がそこに座って応答が返されるのを待っているように見えることを意味します。

私は Twisted + multiprocessing で愚かなことをしていると確信していますが、誰かが私のアプローチの欠陥を説明してくれることを本当に望んでいます。

前もって感謝します!

4

2 に答える 2

12

動作中の呼び出しと動作していない呼び出しの違いは「-n」オプションのみであるため、問題の原因はデーモン化プロセス(「-n」が発生しないようにする)が原因である可能性が高いと思われます。

POSIXでは、デーモン化に関連するステップの1つは、親をフォークして終了させることです。特に、これは、.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自身のハンドラーに置き換えられました。

于 2009-09-24T14:58:46.103 に答える
0

あなたのための可能なアイデア...

デーモン モードで実行すると、twistd は stdin、stdout、および stderr を閉じます。クライアントがこれらに読み書きするものはありますか?

于 2009-09-24T11:32:44.710 に答える