python:windows和linux下multiprocessing模組建立程序的區別

hihibig發表於2024-12-03

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()建立新的子程序,這些子程序有效地繼承父程序的記憶體狀態副本。

這意味著直譯器不需要對作為Process的args傳遞的物件進行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 "", line 1, in
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

相關文章