2012-11-15 125 views
1

我試圖使用cherrypy + multiprocessing(啓動worker'進程')+ gevent(從worker進程中啓動並行的i/o greenlet)組合。看起來最簡單的方法是monkeypatch multiprocessing,因爲greenlet只能在主應用程序中運行。CherryPy,Multiprocessing和Gevent猴子修補程序

但是,它看起來像猴子補丁適用於多處理的一些部分,而不是其他人。這裏是我的樣品的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的類中只產卵greenlets直接
  • 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文檔中與此有關的一些文檔,但找不到任何與此相關的文檔。這只是gevent的猴子補丁不完整嗎?有沒有其他人有類似的問題,有沒有辦法解決它?

+0

我也刪除了CherryPy包裝器,並試着直接調用index_pool()和index_namespace(),結果相同 - 即解釋器掛起前者,並在後一種情況下返回「資源暫時不可用」錯誤消息。 –

+0

下面似乎也討論multiprocessing.Manager()的破壞,不幸的是沒有解決方案:http://stackoverflow.com/questions/8678307/gevent-monkeypatching-breaking-multiprocessing –

回答

1

問題似乎是gevent.socket是非阻塞的結果,這意味着如果X字節沒有立即在套接字上可用,任何socket.recv_bytes(X)調用都會​​拋出該錯誤。具體而言,gevent.socket被設計爲永遠不會阻塞套接字。

multiprocessing問題就出現了,因爲它使用的STDLIB socket模塊,並希望它會阻止,而你已經monkey.patch_all()「d之後,socket模塊已經被取代,multiprocessing.connection不是專門用來對付新的異步行爲。

您可以告訴monkey不要修補socket,但這意味着在應用程序中利用異步套接字的任何事情都可能會因此導致某些性能損失。

要做這個調用patch_allsocket=Falsepatch_all(socket=False)

這不是一個理想的解決方案,因爲你幾乎失去了從首先使用gevent獲得的許多好處。

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多處理工作的解決方案。