python:windows和linux下multiprocessing模块创建进程的区别

 

Windows下面的multiprocessing跟Linux下面略有不同,Linux下面的multiprocessing基于fork,fork之后所有的本地变量都复制一份,因此可以使用任意的全局变量;

在Windows下面,多进程是通过启动新进程完成的,所有的全局变量都是重新初始化的,在运行过程中动态生成、修改过的全局变量是不能使用的。

multiprocessing内部使用pickling传递map的参数到不同的进程,当传递一个函数或类时,pickling将函数或者类用所在模块+函数/类名的方式表示,

如果对端的Python进程无法在对应的模块中找到相应的函数或者类,就会出错。

当你在Interactive Console当中创建函数的时候,这个函数是动态添加到__main__模块中的,在重新启动的新进程当中不存在,所以会出错。

当不在Console中,而是在独立Python文件中运行时,你会遇到另一个问题:由于你下面调用multiprocessing的代码没有保护,

在新进程加载这个模块的时候会重新执行这段代码,创建出新的multiprocessing池,无限调用下去。

解决这个问题的方法是永远把实际执行功能的代码加入到带保护的区域中:if __name__ == '__mian__':

来源:https://www.jb51.net/article/184301.htm

 

在Linux(和其他类似Unix的系统)上,Python的multiprocessing模块是基于fork()创建新的子进程,这些子进程有效地继承父进程的内存状态副本。

这意味着解释器不需要对作为Processargs传递的对象进行pickle,因为子进程已经有了它们的正常形式。

但是Windows没有fork()系统调用,因此multiprocessing模块需要做更多的工作才能使子生成过程正常工作。首先是基于fork()的实现,然后是非分叉的Windows实现。

值得注意的是,Python开发人员经常会觉得,创建子进程与运行Python的平台相差太大有点不适应。所以在Python 3.4中,添加了一个新系统,

允许您select the start method that you would prefer to use。选项有"fork""forkserver""spawn"

在类Unix系统上,"fork"方法仍然是默认的(在早期版本的Python中,它是唯一的实现)。

"spawn"方法是Windows上的默认(也是唯一的)选项,但现在也可以在类Unix系统上使用。

"forkserver"方法是两者之间的一种混合(仅在某些类Unix系统上可用)。

来源:https://www.cnpython.com/qa/69540 后面的回答

【windows】

【windows下正常运行】
import
multiprocessing as mp from time import sleep import os a = 1 def fun(): sleep(2) print("子进程事件",os.getpid()) global a a = 10000 print("a = ",a) if __name__ == "__main__": # 创建进程对象 p = mp.Process(target=fun) # 启动进程 p.start() sleep(3) print("这是父进程") # 回收进程 p.join() print("parent a:", a) #结果 子进程事件 16844 a = 10000 这是父进程 parent a: 1
【windows下ipython运行】
In [65]: import multiprocessing as mp
    ...: from time import sleep
    ...: import os
    ...:
    ...: a = 1
    ...:
    ...: def fun():
    ...:     sleep(2)
    ...:     print("子进程事件",os.getpid())
    ...:     global a
    ...:     a = 10000
    ...:     print("a = ",a)
    ...:
    ...: #创建进程对象
    ...: p = mp.Process(target = fun)
    ...:
    ...: #启动进程
    ...: p.start()
    ...:
    ...: sleep(3)
    ...: print("这是父进程")
    ...:
    ...: #回收进程
    ...: p.join()
    ...: print("parent a:",a)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "d:\software\python\lib\multiprocessing\spawn.py", line 105, in spawn_main
    exitcode = _main(fd)
  File "d:\software\python\lib\multiprocessing\spawn.py", line 115, in _main
    self = reduction.pickle.load(from_parent)
AttributeError: Can't get attribute 'fun' on <module '__main__' (built-in)>
这是父进程
parent a: 1
import multiprocessing as mp
from time import sleep
import os

a = 1

def fun():
    sleep(2)
    print("子进程事件",os.getpid())
    global a
    a = 10000
    print("a = ",a)

#创建进程对象
p = mp.Process(target = fun)

#启动进程
p.start()

sleep(3)
print("这是父进程")

#回收进程
p.join()
print("parent a:",a)

#结果
File "D:\software\Python\lib\multiprocessing\spawn.py", line 136, in _check_not_importing_main
    is not going to be frozen to produce an executable.''')
RuntimeError: 
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.
这是父进程
parent a: 1
[Finished in 3.1s]
在pycharm中运行和这报错相同,但是在按【windows下正常运行】执行一次后,再按此代码执行就正常了

【linux】

import multiprocessing as mp
from time import sleep 
import os

a = 1

def fun():
    sleep(2)
    print("子进程事件",os.getpid())
    global a
    a = 10000
    print("a = ",a)

#创建进程对象
p = mp.Process(target = fun)

#启动进程
p.start() 

sleep(3)
print("这是父进程")

#回收进程
p.join()
print("parent a:",a)

#结果
子进程事件 3953
a =  10000
这是父进程
parent a: 1
import multiprocessing as mp
from time import sleep
import os

a = 1

def fun():
    sleep(2)
    print("子进程事件",os.getpid())
    global a
    a = 10000
    print("a = ",a)


if __name__ == "__main__":
    # 创建进程对象
    p = mp.Process(target=fun)

    # 启动进程
    p.start()

    sleep(3)
    print("这是父进程")

    # 回收进程
    p.join()
    print("parent a:", a)

#结果
子进程事件 3974
a =  10000
这是父进程
parent a: 1

 

posted @ 2021-01-07 18:02  昱成  阅读(3006)  评论(0编辑  收藏  举报