2013-01-08 43 views
3

CherryPy服務器使用線程來處理請求。我的線程服務器中的一種特殊方法非常複雜,而且CPU很繁重,所以我必須使用方法請求線程內的多處理來並行執行。如何將多處理與多線程一起使用?

我想我只是

def expensive_method(self): 
     pool = Pool() 
     x = pool.map(fnc, args) 
     pool.terminate() 

更換

class Server(object) 
    @cherrypy.expose 
    def expensive_method(self): 
     ... 
     x = map(fnc, args) 
     ... 

def fnc(args): 
    # this method doesn't need CherryPy but is expensive to compute 
    ... 

cherrypy.quickstart(Server()) 

(其中正常工作),但不起作用。即使在簡單的情況下,當我不使用在所有的游泳池,

def expensive_method(self): 
     pool = Pool() 
     x = map(fnc, args) # <== no pool here! same as the working example 
     pool.terminate() 

我得到一個異常

[08/Jan/2013:20:05:33] ENGINE Caught signal SIGTERM. 
2013-01-08 20:05:33,919 : INFO : _cplogging:201 : error(CP Server Thread-3) : [08/Jan/2013:20:05:33] ENGINE Caught signal SIGTERM. 
[08/Jan/2013:20:05:33] ENGINE Bus STOPPING 
2013-01-08 20:05:33,920 : INFO : _cplogging:201 : error(CP Server Thread-3) : [08/Jan/2013:20:05:33] ENGINE Bus STOPPING 
[08/Jan/2013:20:05:38] ENGINE Error in 'stop' listener <bound method Server.stop of <cherrypy._cpserver.Server object at 0x1090c3c90>> 
Traceback (most recent call last): 
    File "/Volumes/work/workspace/vew/prj/lib/python2.7/site-packages/cherrypy/process/wspbus.py", line 197, in publish 
    output.append(listener(*args, **kwargs)) 
    File "/Volumes/work/workspace/vew/prj/lib/python2.7/site-packages/cherrypy/process/servers.py", line 223, in stop 
    wait_for_free_port(*self.bind_addr) 
    File "/Volumes/work/workspace/vew/prj/lib/python2.7/site-packages/cherrypy/process/servers.py", line 410, in wait_for_free_port 
    raise IOError("Port %r not free on %r" % (port, host)) 
IOError: Port 8888 not free on '127.0.0.1' 

我認爲這發生在請求結束,之後或期間pool.terminate()

分叉的工作進程不會對服務器或端口做任何事情。有沒有辦法告訴CherryPy和/或多處理忽略「服務器位」? fnc中我不需要任何端口或套接字。

我需要這個工作在OSX + Linux上,使用Python 2.7.1和CherryPy 3.2.2。


進展1:

按西爾的建議下,我嘗試pool = Pool(initializer=cherrypy.server.unsubscribe)。沒有更多的例外,一切工作正常,但在我看到的日誌

[08/Jan/2013:21:16:35] ENGINE Caught signal SIGTERM. 
2013-01-08 21:16:35,908 : INFO : _cplogging:201 : error(CP Server Thread-10) : [08/Jan/2013:21:16:35] ENGINE Caught signal SIGTERM. 
[08/Jan/2013:21:16:35] ENGINE Bus STOPPING 
2013-01-08 21:16:35,909 : INFO : _cplogging:201 : error(CP Server Thread-10) : [08/Jan/2013:21:16:35] ENGINE Bus STOPPING 
[08/Jan/2013:21:16:35] ENGINE Bus STOPPED 
2013-01-08 21:16:35,909 : INFO : _cplogging:201 : error(CP Server Thread-10) : [08/Jan/2013:21:16:35] ENGINE Bus STOPPED 
[08/Jan/2013:21:16:35] ENGINE Bus EXITING 
2013-01-08 21:16:35,909 : INFO : _cplogging:201 : error(CP Server Thread-10) : [08/Jan/2013:21:16:35] ENGINE Bus EXITING 
[08/Jan/2013:21:16:35] ENGINE Bus EXITED 
2013-01-08 21:16:35,910 : INFO : _cplogging:201 : error(CP Server Thread-10) : [08/Jan/2013:21:16:35] ENGINE Bus EXITED 

這樣好嗎?難道這會產生任何麻煩(比如說,當同時在不同線程中提供多個請求時)?


進展2:

其實上面的葉子空閒進程背後偶爾:(因此,這是行不通的精細奇怪的是,這些閒置的過程是由Pool催生,所以他們應該是守護進程。但他們甚至殺害父後實際活路


正在進行中3:

我感動分岔(= Pool()調用)在請求處理方法之外,但之後初始化所有必要的狀態(以便工作進程可以看到這個狀態)。沒有更多的錯誤或例外。

底線:多處理和多線程不能一起工作。

回答

3

「自我」指的是哪種類型的對象?你在什麼時候初始化並開始你的分叉過程?也許多一些代碼可以幫助診斷問題。

好吧,這只是罰款:

import multiprocessing 
import os 
import time 

import cherrypy 

def run_in_sub_proc(size): 
    for i in range(size): 
     print os.getpid(), i 
     time.sleep(1) 

pool = multiprocessing.Pool(2) 

class Root(object): 
    @cherrypy.expose 
    def index(self): 
     pool.map_async(run_in_sub_proc, (3, 5)) 

if __name__ == '__main__': 
    cherrypy.engine.subscribe('stop', pool.join) 
    cherrypy.quickstart(Root()) 
+0

感謝。你可以嘗試使fnc成爲實際的模塊級功能而不是方法嗎? –

+0

我可能不會在CherryPy頁面處理程序中創建池。線程和多進程並不總是最好的朋友,因爲我最近了解到http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them –

+0

該死的我還沒有正確地閱讀你的初始文章。如果你不需要服務器,只需在快速啓動調用之前執行:'cherrypy.server.unsubscribe()'。 –