Windows下面的multiprocessing跟Linux下面略有不同,Linux下面的multiprocessing基於fork,fork之后所有的本地變量都復制一份,因此可以使用任意的全局變量;
在Windows下面,多進程是通過啟動新進程完成的,所有的全局變量都是重新初始化的,在運行過程中動態生成、修改過的全局變量是不能使用的。
multiprocessing內部使用pickling傳遞map的參數到不同的進程,當傳遞一個函數或類時,pickling將函數或者類用所在模塊+函數/類名的方式表示,
如果對端的Python進程無法在對應的模塊中找到相應的函數或者類,就會出錯。
當你在Interactive Console當中創建函數的時候,這個函數是動態添加到__main__模塊中的,在重新啟動的新進程當中不存在,所以會出錯。
當不在Console中,而是在獨立Python文件中運行時,你會遇到另一個問題:由於你下面調用multiprocessing的代碼沒有保護,
在新進程加載這個模塊的時候會重新執行這段代碼,創建出新的multiprocessing池,無限調用下去。
解決這個問題的方法是永遠把實際執行功能的代碼加入到帶保護的區域中:if __name__ == '__mian__':
在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 "<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