2

私はcherrypy+マルチプロセッシング(worker'processes'を起動するため)+ gevent(worker'processes'内から並列I/ Oグリーンレットを起動するため)の組み合わせを使用しようとしています。グリーンレットはメインのアプリケーションプロセスでのみ動作するため、これを行う最も簡単な方法は、モンキーパッチマルチプロセッシングです。

ただし、モンキーパッチはマルチプロセッシングの一部で機能し、他の部分では機能しないようです。これが私のサンプルCherryPyサーバーです:

from gevent import monkey
monkey.patch_all()

import gevent
import cherrypy
import multiprocessing

def launch_testfuncs():
    jobs = [gevent.spawn(testfunc)
            for i in range(0, 12)]

    gevent.joinall(jobs, timeout=10)

def testfunc():
    print 'testing'

class HelloWorld(object):
    def index(self):
        launch_testfuncs()

        return "Hello World!"
    index.exposed = True

    def index_proc(self):
        proc = multiprocessing.Process(target=launch_testfuncs)
        proc.start()
        proc.join()

        return "Hello World 2!"
    index_proc.exposed = True

    def index_pool(self):
        pool = multiprocessing.Pool(1)
        return "Hello World 3!"
    index_pool.exposed = True

    def index_namespace(self):
        manager = multiprocessing.Manager()
        anamespace = manager.Namespace()
        anamespace.val = 23
        return "Hello World 4!"
    index_namespace.exposed = True


cherrypy.quickstart(HelloWorld())

モンキーパッチを適用すると、次のように動作します。

  • index--cherrypyクラス内から直接グリーンレットをスポーンするだけです
  • index_proc-を使用multiprocessing.Processして新しいプロセスを起動し、そのプロセスからグリーンレットを生成します

以下に問題があります。

  • index_pool-起動しますmultiprocessing.Pool-ハングし、決して戻りません
  • index_namespace-multiprocessing.Manager名前空間を初期化して、ワーカーのプール/コレクション内の共有メモリを管理します-次のエラーメッセージを返します:

    [15/Nov/2012:17:19:31] HTTP Traceback (most recent call last):
      File "/Library/Python/2.7/site-packages/cherrypy/_cprequest.py", line 656, in respond
    response.body = self.handler()
      File "/Library/Python/2.7/site-packages/cherrypy/lib/encoding.py", line 188, in __call__
    self.body = self.oldhandler(*args, **kwargs)
      File "/Library/Python/2.7/site-packages/cherrypy/_cpdispatch.py", line 34, in __call__
    return self.callable(*self.args, **self.kwargs)
      File "server.py", line 39, in index_namespace
    anamespace = manager.Namespace()
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/managers.py", line 667, in temp
    token, exp = self._create(typeid, *args, **kwds)
      File "/System/Library/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 "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/connection.py", line 175, in Client
    answer_challenge(c, authkey)
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/connection.py", line 414, in answer_challenge
    response = connection.recv_bytes(256)        # reject large message
    IOError: [Errno 35] Resource temporarily unavailable
    

gevent docsでこれに関連するいくつかのドキュメントを見つけようとしましたが、これを扱っているものは見つかりませんでした。geventのモンキーパッチが不完全なだけですか?他の誰かが同様の問題を抱えていて、それを回避する方法はありますか?

4

2 に答える 2

1

gevent.socketこの問題は、非ブロッキングの結果であると思われます。つまり、ソケットでバイトがすぐに利用できないsocket.recv_bytes(X)場合、どの呼び出しでもそのエラーがスローされます。X具体的にはgevent.socket、ソケットをブロックしないように設計されています。

の問題multiprocessingは、stdlibsocketモジュールを使用し、ブロックされていると想定しているために発生しますがmonkey.patch_all()socketモジュールは置き換えられておりmultiprocessing.connection、新しい非同期動作を処理するようには設計されていません。

monkeyパッチを適用しないように指示することはできますsocketが、アプリケーションで非同期ソケットを利用していたものはすべて、これが原因でパフォーマンスがいくらか低下する可能性があることを意味します。

この呼び出しを行うpatch_allにはsocket=Falsepatch_all(socket=False)

geventこれは理想的な解決策ではありません。そもそも使用することで得られるメリットの多くを失うからです。

于 2013-02-06T19:52:43.943 に答える
1

私はあなたと同じ問題に遭遇しました。私の解決策は、multiprocessing.Process()を使用して固定数のプロセスを生成したところです。そして最後に全員に参加し、完了するのを待ちます。

#!/usr/bin/env python
# encoding: utf-8

from gevent import monkey
monkey.patch_all()

import gevent
import multiprocessing as mp


NUM = 10


def work(i):
    jobs = [gevent.spawn(func, i)
            for i in range(0, 12)]
    gevent.joinall(jobs)
    print "{} Done {}".format(mp.current_process().name, i)


def func(x):
    print "Gevent: {}".format(x)

def main():

    processes = [mp.Process(name="Process-{}".format(i), target=work, args=(i,)) for i in xrange(NUM)]

    for process in processes:
        process.start()

    for process in processes:
        process.join()


if __name__ == '__main__':
    main()

出力

Gevent: 0
Gevent: 1
Gevent: 2
Gevent: 3
Gevent: 4
Gevent: 5
Gevent: 6
Gevent: 7
Gevent: 8
Gevent: 9
Gevent: 10
Gevent: 11
Process-0 Done 11
Gevent: 0
Gevent: 1
Gevent: 2
Gevent: 3
Gevent: 4
Gevent: 5
Gevent: 6
Gevent: 7
Gevent: 8
Gevent: 9
Gevent: 10
Gevent: 11
Process-1 Done 11
Gevent: 0
Gevent: 1
Gevent: 2
Gevent: 3
Gevent: 4
Gevent: 5
Gevent: 6
Gevent: 7
Gevent: 8
Gevent: 9
Gevent: 10
Gevent: 11
Process-2 Done 11
Gevent: 0
... ...

これが、マルチプロセッシングを使用するgeventのソリューションです。

于 2015-12-09T12:07:08.983 に答える