【问题标题】:How to use multiprocessing together with multithreading?如何将多处理与多线程一起使用?
【发布时间】:2013-01-08 19:17:10
【问题描述】:

CherryPy 服务器使用线程来处理请求。我的线程服务器中的一种特殊方法非常复杂且占用大量 CPU,因此我必须从方法请求线程内部使用多处理来并行化执行。

我以为我会替换

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 = pool.map(fnc, args)
        pool.terminate()

但这不起作用。即使在更简单的情况下,当我根本不使用游泳池时,

    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:

按照 Sylvain 的建议,我尝试了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() 调用)移到了请求处理方法之外,但是初始化了所有必要的状态之后(以便工作进程可以看到这个状态)。不再有错误或异常。

底线:多处理和多线程不能一起工作。

【问题讨论】:

    标签: python multithreading multiprocessing cherrypy


    【解决方案1】:

    “self”指的是哪种类型的对象?你在什么时候初始化并开始你的分叉进程?也许更多的代码将有助于诊断问题。

    好的,这很好用:

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

    【讨论】:

    • 谢谢。您可以尝试将 fnc 设为实际的模块级函数而不是方法吗?
    • 我可能不会在 CherryPy 页面处理程序中创建池。我最近了解到,线程和多进程并不总是最好的朋友linuxprogrammingblog.com/…
    • 该死,我没有正确阅读您的初始帖子。如果您不需要服务器,只需在调用快速入门之前执行以下操作:cherrypy.server.unsubscribe()
    • 嗯,master 需要服务器(=*is* 服务器),但池中的分叉工人不需要。
    • 我试过pool = Pool(initializer=cherrypy.server.unsubscribe),没有更多异常!日志中仍有一些奇怪的错误,将更新问题,感谢您的评论。
    猜你喜欢
    • 2019-03-16
    • 2019-11-27
    • 2021-05-22
    • 2012-03-04
    • 1970-01-01
    • 2011-11-24
    • 2011-09-17
    • 1970-01-01
    相关资源
    最近更新 更多