Python多進程
Python中進程創(chuàng)建方式有兩種:
- fork:使用Python提供的os模塊。
pid = os.fork();
pid即為創(chuàng)建出的子進程
Python在創(chuàng)建進程時會返回兩次;一般方法只返回一次,Python分別在子進程、父進程中分別返回創(chuàng)建出的進程的ID。
Unix/Linux操作系統(tǒng)提供了一個fork()系統(tǒng)調(diào)用,它非常特殊。普通的函數(shù)調(diào)用,調(diào)用一次,返回一次,
但是fork()調(diào)用一次,返回兩次,因為操作系統(tǒng)自動把當前進程(稱為父進程)復(fù)制了一份(稱為子進程),
然后,分別在父進程和子進程內(nèi)返回。
子進程返回的ID一直為0
父進程返回的ID則是創(chuàng)建出的進程ID,父進程會保存該ID。
pid = os.fork();
if pid == 0:
print('我是子進程我的編號是%1s,我的父進程的編號是%2s' % (os.getpid(), os.getppid()))
else:
print('我是父進程我的編號是%1s,我剛剛創(chuàng)建了一個子進程,編號是%2s' % (os.getpid(), pid))
輸出結(jié)果:
我是子進程我的編號是12688,我的父進程的編號是12687
我是父進程我的編號是12687,我剛剛創(chuàng)建了一個子進程,編號是12688
2.使用multiprocessing模塊提供的Process、Pool 動態(tài)批量創(chuàng)建進程
為什么又要提出一個multiprocessing模塊創(chuàng)建進程,單單fork不就OK。
因為。。。因為windows不支持直接fork進程。<font color = red >(劃重點,這個要考)</font>而linux/Unix系列支持。(所以,人生苦短,使用mac學(xué)習Python)
使用Process創(chuàng)建也很簡單。
# 使用process對象進行創(chuàng)建進程
def run_proc(name):
print('創(chuàng)建進程的名字為%s' % (name))
if __name__ == '__main__':
print('-----------------------')
print('創(chuàng)建子進程的父進程ID是%s' % (os.getpid()))
#run_proc 是進程需要執(zhí)行的任務(wù)的方法名
#args 是run_proc方法需要的參數(shù)
p = Process(target=run_proc, args=('test',))
p.start()
p.join()
print('執(zhí)行完了')
運行結(jié)果:
-----------------------
創(chuàng)建進程的名字為test
執(zhí)行完了
創(chuàng)建成功之后,直接<font color= red>p.start()</font>
<font color = red >p.join()</font>用作進程同步(線程中也要用到這個方法)。意為進程此時等待,直到子進程執(zhí)行完,再繼續(xù)執(zhí)行后續(xù)代碼。
這樣就實現(xiàn)了創(chuàng)建進程的代碼。很清晰,很清晰,很簡單。
接下來,就要進入高級的多進程創(chuàng)建了。
Pool
如果你有多進程的需求,就不要使用上述一個一個的創(chuàng)建了,
使用multiprocessing提供的Pool進程池進行多進程的創(chuàng)建。安全,文明,優(yōu)雅。
from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p = Pool(2)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
# 必須要先進行close,然后才能進行join()
p.close()
p.join()
print('All subprocesses done.')
執(zhí)行結(jié)果:
Parent process 12917.
Waiting for all subprocesses done...
Run task 0 (12920)...
Run task 1 (12921)...
Waiting for all subprocesses done...
Run task 0 (12922)...
Run task 1 (12923)...
Task 1 runs 0.29 seconds.
Run task 2 (12923)...
Task 1 runs 0.96 seconds.
Run task 2 (12921)...
Task 0 runs 1.01 seconds.
Run task 3 (12920)...
Task 2 runs 1.03 seconds.
Run task 4 (12921)...
Task 3 runs 1.17 seconds.
Task 0 runs 2.22 seconds.
Run task 3 (12922)...
Task 2 runs 2.13 seconds.
Run task 4 (12923)...
Task 4 runs 1.87 seconds.
All subprocesses done.
直接使用p = Pool(2)創(chuàng)建一個進程數(shù)為2的進程池。
p.apply_async(long_time_task, args=(i,))
將待執(zhí)行的任務(wù)與進程綁定<font color = red >apply_async</font>。
p.close():
對Pool對象調(diào)用join()方法會等待所有子進程執(zhí)行完畢,
調(diào)用join()之前必須先調(diào)用close(),
調(diào)用close()之后就不能繼續(xù)添加新的Process了。