web-dev-qa-db-ja.com

マルチプロセッシングを破るGeventモンキーパッチ

マルチプロセッシングのプールを使用してプロセスのグループを実行しようとしています。各プロセスは、グリーンレットのgeventプールを実行します。これは、ネットワークアクティビティが多いだけでなく、CPUアクティビティも多いため、帯域幅とすべてのCPUコアを最大化するには、複数のプロセスとgeventの非同期モンキーパッチが必要です。マルチプロセッシングのマネージャーを使用して、データを処理するためにプロセスがアクセスするキューを作成しています。

コードの簡略化されたフラグメントは次のとおりです。

import multiprocessing

from gevent import monkey
monkey.patch_all(thread=False)

manager = multiprocessing.Manager()
q = manager.Queue()

これが生成する例外です:

Traceback (most recent call last):
  File "multimonkeytest.py", line 7, in <module>
    q = manager.Queue()
  File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/managers.py", line 667, in temp
    token, exp = self._create(typeid, *args, **kwds)
  File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/managers.py", line 565, in _create
    conn = self._Client(self._address, authkey=self._authkey)
  File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/connection.py", line 175, in Client
    answer_challenge(c, authkey)
  File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/connection.py", line 409, in answer_challenge
    message = connection.recv_bytes(256)         # reject large message
 IOError: [Errno 35] Resource temporarily unavailable

これは、通常のソケットモジュールとgeventのソケットモジュールの動作の違いによるものだと思います。

サブプロセス内でモンキーパッチを適用すると、キューは正常に作成されますが、サブプロセスがキューからget()を取得しようとすると、非常によく似た例外が発生します。サブプロセスで多数のネットワーク要求を実行するため、ソケットにモンキーパッチを適用する必要があります。

私のバージョンのgeventは、最新のものだと思います。

>>> gevent.version_info
(1, 0, 0, 'alpha', 3)

何か案は?

24
user964375

monkey.patch_all(thread=False, socket=False)を使用する

私は同様の状況で同じ問題に遭遇し、これをpatch_socket()関数の下の_gevent/monkey.py_の115行目まで追跡しました:__socket.socket = socket.socket_。この行をコメントアウトすると、破損を防ぐことができます。

これは、geventがstdlib socketライブラリを独自のものに置き換える場所です。 _multiprocessing.connection_はsocketライブラリを非常に広範囲に使用しており、明らかにこの変更に寛容ではありません。

具体的には、インポートしたモジュールが_socket=False_を設定せずにgevent.monkey.patch_all()呼び出しを実行するシナリオでこれが発生します。私の場合、これを行ったのはgrequestsであり、このエラーを修正するには、ソケットモジュールのパッチをオーバーライドする必要がありました。

17
Nisan.H

Geventのコンテキストでマルチプロセッシングを適用すると、残念ながら問題が発生することが知られています。ただし、あなたの論理的根拠は合理的です(「多くのネットワークアクティビティだけでなく、多くのCPUアクティビティ」)。よろしければ、 http://gehrcke.de/gipc をご覧ください。これは主にユースケース向けに設計されています。 gipcを使用すると、完全にgeventを認識する子プロセスをいくつか簡単に生成し、パイプを介して相互に、および/または親と協調的に通信させることができます。

ご不明な点がございましたら、お気軽にお問い合わせください。

元のキューを使用する場合、コードはモンキーパッチを適用したソケットでも正常に機能します。

import multiprocessing

from gevent import monkey
monkey.patch_all(thread=False)

q= multiprocessing.Queue()
2

交換用のNoseMultiprocessプラグインを作成しました。これは、あらゆる種類のクレイジーなGeventベースのパッチでうまく機能するはずです。

https://pypi.python.org/pypi/nose-gevented-multiprocess/

https://github.com/dvdotsenko/nose_gevent_multiprocess

  • ワーカープロセスのmultiprocess.forkからプレーンsubprocess.popenに切り替えます(モジュールレベルの誤って共有されたオブジェクトの問題を修正します)
  • マスターからクライアントへのRPCについて、multiprocess.QueueからJSON-RPC overHTTPに切り替えました
  • これにより、理論的にはテストを複数のマシンに分散させることができます。
1
ddotsenko

提供されたコードは、Windows7で機能します。

編集:

Ubuntu 11.10 VPSでコードを試したところ、同じエラーが発生したため、以前の回答を削除しました。

のように見えます イベントレットにもこの問題があります

1
reclosedev