推荐学习书目
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
youthfire
V2EX  ›  Python

对 Python 里多进程池用法有点迷茫

  •  
  •   youthfire · Aug 6, 2020 · 3956 views
    This topic created in 2133 days ago, the information mentioned may be changed or developed.

    大致看了下多线程和多进程的关系 多线程里同名变量写起来容易冲突麻烦,所以就用了多进程.这个多进程用起来有点迷茫 (运行环境是 Mac)

    我多进程的写发如下

    p = Pool(processes=6)
    p.apply_async(过程名,参数)
    p.close()
    p.join()
    
    • 迷惑一:只要程序前不加 if name == 'main':,根本无法跑起来.报各种错误
    • 迷惑二:程序全都跑完了,要卡很久才结束(命令都执行完了,就是不跳回待输入命令行状态)
    • 迷惑三:是不是核数应该填最大值?(比如我是 8),还是说一般有必要保留冗余呢?
    22 replies    2023-02-01 12:09:57 +08:00
    yngzij
        1
    yngzij  
       Aug 6, 2020
    由于 Windows 没有 fork,因此多处理模块将启动一个新的 Python 进程并导入调用模块 没有 if name == 'main' 会重复创建副本。
    youthfire
        2
    youthfire  
    OP
       Aug 6, 2020 via iPhone
    @yngzij #1 我的运行环境也是 Mac 平台,你的意思是不管运行环境如何,Python 就是这样设计的?
    XiaoxiaoPu
        3
    XiaoxiaoPu  
       Aug 6, 2020
    @youthfire Python 版本是什么?最新的 Python 多进程有三种模式,spawn 、fork 、forkserver,不同模式行为是不一样的。Python 3.8 在 macOS 下默认模式为 spawn,子进程是一个全新的解释器。
    crella
        4
    crella  
       Aug 6, 2020 via Android
    找个类把同名变量包起来可以吗?
    lithbitren
        5
    lithbitren  
       Aug 6, 2020   ❤️ 1
    核数不填的时候默认最大,卡很久结束没碰到过,几个进程应该时几十到几百毫秒内结束。
    if name == 'main'必须加,不然会重复创建对象副本,每个进程的对象都是单独运算的。
    多进程有些函数需要些全局 def,反而是副本才能正常调用,用局部或 lambda 可能会 pickle 失败,其实正常写 py 不管啥脚本都建议加 main 的判断块,就跟其他语言包进 main 函数里面一样
    neoblackcap
        6
    neoblackcap  
       Aug 6, 2020
    @lithbitren 重复创建对象副本是什么意思?
    youthfire
        7
    youthfire  
    OP
       Aug 6, 2020 via iPhone
    @XiaoxiaoPu #3 谢谢分享,我用的 3.8.5 。
    youthfire
        8
    youthfire  
    OP
       Aug 6, 2020 via iPhone
    @lithbitren #5 谢谢指点。我也就放了 12 个简单的 web 抓取数据进程,就是都跑完了,各进程都输出结果了,然后不动了,过很久最终结束。可能的话,我晚点放完整代码上来。
    XiaoxiaoPu
        9
    XiaoxiaoPu  
       Aug 6, 2020
    @youthfire 抓取数据的话,简单点可以用多线程的,坑少一点
    imn1
        10
    imn1  
       Aug 6, 2020
    1.不需要 main,但启动要在顶级,我也说不清楚那些术语
    举例,在根建一个 fun,里面写 multiprocess,然后在其他地方传参过去调用这个 fun
    multiprocess 写在类方法里面,运行会报错,但按上面的写法,类方法里面调用这个 fun 则可以正常运行
    2.不晓得,是不是 IO 太多?
    3.processes 这个貌似只是进程数吧,chrome 可以起几十个进程呢,当然多了也是问题

    我只是知其然,不知其所以然,会写会抄,但搞不清状况,说错了勿怪
    非 Mac 用户
    renmu123
        11
    renmu123  
       Aug 6, 2020 via Android
    如果是 io 密集型推荐使用多线程,会比多进程快那么一丢丢,多线程也是有池的,在多进程模块里,你翻一下文档
    XiaoxiaoPu
        12
    XiaoxiaoPu  
       Aug 6, 2020
    spawn 、forkserver 模式下,进程的 run 函数和参数需要进程间通信来传递,这个过程会用 pickle 来序列化、反序列化,所以 run 函数和参数会受 pickle 的限制,pickle 支持如下数据类型

    * None, True, and False
    * integers, floating point numbers, complex numbers
    * strings, bytes, bytearrays
    * tuples, lists, sets, and dictionaries containing only picklable objects
    * functions defined at the top level of a module (using def, not lambda)
    * built-in functions defined at the top level of a module
    * classes that are defined at the top level of a module
    * instances of such classes whose __dict__ or the result of calling __getstate__() is picklable (see section Pickling Class Instances for details).
    XiaoxiaoPu
        13
    XiaoxiaoPu  
       Aug 6, 2020
    「程序前不加 if name == 'main'」这种情况下,你的 python 文件就没法被 import,因为 import 隐含了运行代码,死循环了
    lithbitren
        14
    lithbitren  
       Aug 6, 2020
    抓数据还是建议多线程或协程,多进程开几个没啥体感,开几十几百个就知道什么叫肉眼可见的慢了,协程线程一般个人项目开多少都没啥体感,而且协程线程数据可以直接共享,不用像多进程那样考虑 pickle 的问题。
    计算密集也不一定多进程,单核睿频一般能到 1.5-1.8 倍的处理速度,个人机全跑满实际也就多个 3-6 倍,但要考虑的东西复杂得多,进程间的各种传值操作也有不小开销,不是计算特别耗时的项目,还不如直接单进程跑线程协程。
    youthfire
        15
    youthfire  
    OP
       Aug 6, 2020
    @imn1 @renmu123 @XiaoxiaoPu 感谢分享心得和理解
    @lithbitren 说得很量化,我会试试线程或协程,谢谢
    Te11UA
        16
    Te11UA  
       Aug 6, 2020
    @lithbitren 那这样的话,单进程不就利用不了多核麽?
    lithbitren
        17
    lithbitren  
       Aug 6, 2020
    @Te11UA 多进程麻烦啊,比如抓数据一条几秒抓回来,处理数据就几到几十毫秒,需要并行处理的机会也不一定太高,个人电脑多核计算对这几十毫秒意义不大,不如直接单进程省事,想用也可以,只是不推荐而已。
    youthfire
        18
    youthfire  
    OP
       Aug 6, 2020
    晚上特地去试验了下协程,用的 gevent.joinall([gevent.spawn(函数)若干]),整体感觉就跟没用一样,比多进程慢很多. 准备用一下多线程
    lithbitren
        19
    lithbitren  
       Aug 7, 2020
    @youthfire 现在 Python 讲的协程基本都是官办协程了,不过 gevent 爬虫可以直接用 grequests,也不费事。
    wuwukai007
        20
    wuwukai007  
       Aug 7, 2020 via Android
    @lithbitren grequests 挺占内存的
    youthfire
        21
    youthfire  
    OP
       Aug 7, 2020 via iPhone
    @lithbitren #19 改用了多线程池后发现效果确实不错,速度甚至更快,也没有多进程池那最后卡顿了(虽然不明白卡顿是什么原因)
    phoulx
        22
    phoulx  
       Feb 1, 2023 via iPhone
    卡顿是因为 apply_async 返回 AsyncResult 对象,但是运行结果实际在 join()时才执行得到。AsyncResult 可以手动 get()结果,也可以加上 callback 参数来指定回调动作。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5880 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 52ms · UTC 06:15 · PVG 14:15 · LAX 23:15 · JFK 02:15
    ♥ Do have faith in what you're doing.