如何确保一个类是跨进程安全的? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
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
LeeReamond

如何确保一个类是跨进程安全的?

  •  
  •   LeeReamond Apr 19, 2022 3308 views
    This topic created in 1471 days ago, the information mentioned may be changed or developed.

    需求,一个异步脚本里大量使用run_in_executor()封装同步调用,然后脚本本身用了 os.fork()搞出很多子进程。理论上最好所有子进程共享同一个线程池而不是每个进程单独拥有一个线程池。

    import asyncio, time, os from concurrent.futures import ThreadPoolExecutor executor = ThreadPoolExecutor() def sync_call(x): time.sleep(0.1) return x+1 async def main(): loop = asyncio.get_running_loop() while True: res = await asyncio.gather(*(loop.run_in_executor(executor, sync_call, x) for x in range(100))) assert res == [_ for _ in range(1,101)] print(True) if __name__ == '__main__': for _ in range(16): pid = os.fork() if pid == 0: break asyncio.run(main()) 

    简化下来大概是这样的代码,其中线程池是自己几年前写的,当时确保了在单进程内使用多线程的情况下是绝对安全的,现在已经看不懂代码了,怎样才能知道多进程的情况下是否能确保安全呢?

    上文这个代码拿来跑当测试,倒是也没报错,但是我怎么知道它是不是刚好没遇到特殊情况所以没坑。。

    12 replies    2022-04-19 20:24:22 +08:00
    rb6221
        1
    rb6221  
       Apr 19, 2022
    太经典了,自己写的代码过一段时间就看不懂了
    gfreezy
        2
    gfreezy  
       Apr 19, 2022
    进程之间不共享(好像除了 fd 以外的)任何东西,包括线程。
    fcfangcc
        3
    fcfangcc  
       Apr 19, 2022
    进程之间应该是无法共享线程池。为什么要 fork 多个子进程,直接启动多个 task 不就好了吗
    fcfangcc
        4
    fcfangcc  
       Apr 19, 2022
    asyncio.wait([main() for i in range(16)])
    qbqbqbqb
        5
    qbqbqbqb  
       Apr 19, 2022
    用多进程的话,传递给子进程 target 函数参数和传回来的返回值必须是能用 pickle 序列化、反序列化的,或者是 multiprocessing 库里面的 Queue, Value, Array 之类的专用的进程间通信工具。不能随便传递其它对象。

    另外就是子进程也不能随便用全局变量、全局对象(常量可以用,有状态的对象慎用),因为子进程里全局对象的初始状态是有区别的,而且修改之后也不会同步到其它进程。

    Python 多进程有三种模式 fork, spawn, forkserver:
    1 ) fork 模式子进程会继承此时主进程的状态(相当于当前 Python 分裂成两个,其中主进程继续执行当前函数,子进程跳到 target 函数)
    2 ) spawn 和 forkserver 模式子进程为程序刚初始化后的状态(相当于重新启动了一个 Python import 了所有库,然后不执行__main__直接跳到 target 函数开始执行)。

    Linux 默认 fork ,Mac py3.8 以后默认 spawn, Windows 只支持 spawn 。
    lolizeppelin
        6
    lolizeppelin  
       Apr 19, 2022   1
    你这需求老老实实写线程. 协程都别写

    觉得 python 线程不行要么换语言要么自己写 c 库

    什么跨进程共享线程池都出来了
    qbqbqbqb
        7
    qbqbqbqb  
       Apr 19, 2022
    @qbqbqbqb #5 是针对 Multiprocessing 多进程的。os.fork()就简单粗暴很多,子进程继承 fork 时的状态,之后对象状态的改变就不共享了,所以后来创建的线程池肯定是每个进程一个。想要统一池子还不如直接用 Multiprocessing 里的进程池。
    cyrbuzz
        8
    cyrbuzz  
       Apr 19, 2022
    多进程共享同一个线程即使可以的话优势在什么地方?这是为了解决什么问题= =。
    lyz1990
        9
    lyz1990  
       Apr 19, 2022
    进程能共享线程池么?
    xuanbg
        10
    xuanbg  
       Apr 19, 2022
    多实例化几个对象不行么。。。非要跨什么进程。
    lolizeppelin
        11
    lolizeppelin  
       Apr 19, 2022
    @qbqbqbqb
    Multiprocessing 就是个大坑,读下 Multiprocessing 代码就知道了

    Multiprocessing 就适合跑下简单业务,稍微复杂点的拿 Multiprocessing 跑简直找死
    LeeReamond
        12
    LeeReamond  
    OP
       Apr 19, 2022
    @qbqbqbqb
    @fcfangcc
    @janus77
    @gfreezy
    @lolizeppelin
    @xuanbg 异步是为了让过程调用受网络管理,需求是 CPU 密集型任务所以使用 fork 多进程,楼上老哥说得对,我试了一下好像真的除了 fd 以外不共享任何数据,跟我记忆中有些偏差(我印象中不特意创建进程间可共享内存也有同指向发生,试了下好像除了虚拟内存表以外物理内存表也全拷贝了,完全的互不相干。。)


    关于代码写完过几年看不懂的问题,因为是开源项目其实当时还写了蛮详细的注释的,只不过是用英文写的,现在看注释一大坨一大坨像看论文一样实在不想看。可能这个故事教育我们就是不要好面子写英文,外国人看不看得懂不是最重要的,自己能看懂才是。。
    About     Help     Advertise     Blog     API     FAQ     Solana     929 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 44ms UTC 21:27 PVG 05:27 LAX 14:27 JFK 17:27
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86