V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
tianshilei1992
V2EX  ›  Python

Python 下多进程的问题

  •  
  •   tianshilei1992 ·
    shiltian · 2017-04-15 14:08:14 +08:00 · 2998 次点击
    这是一个创建于 2813 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题背景

    现在有一个 Python 程序,这个程序里面 import abc 模块,该是用 C++ 编写的,编写的时候还使用了 OpenMP 多线程库。直接通过 python xxx.py --options OPTIONS 来运行,可以感受到多线程带来性能上的提升。但是这个 abc 模块的编写似乎有一点问题,在某些参数条件下会崩溃,这个崩溃不是抛出异常,而是整个 Python 程序(解释器)的崩溃,没有任何错误提示。OPTIONS 最终也是由 __main__ 函数负责解析,调用里面的函数 func(args...) 来完成。

    我们需要测试不同的参数组合,并且不想因为某一组参数导致整个测试程序的崩溃。所以我们就另外编写了一个 Python 程序,里面 from xxx import func,然后想要通过派生一个新的进程来执行 func,防止因为崩溃导致主进程的崩溃。

    multiprocessing 方式

    首先想到的是使用 multiprocessing 方式,相关的代码如下:

    from multiprocessing import Process
    from xxx import func
    
    p = Process(target=func, args=(__OPTIONS__)) # __OPTIONS__ 为想要传入的参数
    p.start()
    p.join(300) # 设置主进程阻塞 300 秒
    while p.is_alive():
      p.terminate()
    # 处理 IPC 回收数据
    

    设定超过 300 秒就算失败。现在的问题是,使用这种方式执行 func 后,看起来 func 的执行失去了并行能力,执行其中的一个运算会卡住,但是这个卡住是真卡住了还是因为没有运算完,这个无从得知。

    subprocess 方式

    其次想到的就是利用 subprocess 来做,相关代码如下:

    import subprocess
    from xxx import func
    
    p = subprocess.Popen('python xxx.py --options OPTIONS', shell=True)
    # 处理超时以及从 STDOUT 回收数据
    

    利用这种方式 xxx.py 可以正常的并行执行,但是想要回收数据,只能通过 STDOUT 或者写入文件来进行。

    问题

    为什么通过 multiprocess.Process 执行的函数多进程会看起来丧失并行能力?

    10 条回复    2017-04-16 08:10:39 +08:00
    rogerchen
        1
    rogerchen  
       2017-04-15 14:29:44 +08:00
    子进程在的 python 解释器都挂了还能指望 join 能正常工作么?
    pagxir
        2
    pagxir  
       2017-04-15 14:36:48 +08:00 via Android
    你明显不会写异步处理的程序。
    gouchaoer
        3
    gouchaoer  
       2017-04-15 14:44:47 +08:00 via Android
    用 exec 调用来?
    gouchaoer
        4
    gouchaoer  
       2017-04-15 14:46:17 +08:00 via Android
    py 下没试过。。。。 php 下用异步的类 exec 调用可以开 n 个 php 程序,具体 api 是 proc_open 。。。。 py 下肯定有这样的 api
    tianshilei1992
        5
    tianshilei1992  
    OP
       2017-04-15 15:00:40 +08:00
    @rogerchen 通过 spawn 方式的 Process 不是重新开一个新的 Python 解释器来做吗?不过似乎 Python 2 不支持这种定义?
    tianshilei1992
        6
    tianshilei1992  
    OP
       2017-04-15 15:01:06 +08:00
    @pagxir 没有经验,希望多多指教。
    tianshilei1992
        7
    tianshilei1992  
    OP
       2017-04-15 15:04:30 +08:00
    @gouchaoer 查到 Python 下可以用 pool.apply_async 似乎是同样的工作,周一去试试。
    其实我就想让主进程调用完了就阻塞的。
    yucongo
        8
    yucongo  
       2017-04-15 15:37:55 +08:00   ❤️ 1
    试试
    p.daemon = True
    p.start()
    wwqgtxx
        9
    wwqgtxx  
       2017-04-15 16:10:23 +08:00
    如果你自己看过 multiprocess.Process 的源代码,他内部是有子进程和父进程的通讯的,而你的子程序可能因为某些原因导致了通讯未能正常进行,所以就表选出卡住了的状态,而一个正常运行的 python 解析器是肯定可以保证通讯正常进行的
    另外,实际上 multiprocess.Process 内部依然使用了 Popen 来实现,所以你自己模仿实现一个也没啥毛病
    tianshilei1992
        10
    tianshilei1992  
    OP
       2017-04-16 08:10:39 +08:00 via iPhone
    @wwqgtxx 好的 谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2747 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 02:02 · PVG 10:02 · LAX 18:02 · JFK 21:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.