python建立子程序的幾種常用方式(fork, Process,程序池)
linux下使用fork()建立子程序
Linux 作業系統提供了一個 fork() 函式用來建立子程序,這個函式很特殊,呼叫一次,返回兩次,因為作業系統是將當前的程序(父程序)複製了一份(子程序),然後分別在父程序和子程序內返回。子程序永遠返回0,而父程序返回子程序的 PID(大於0)。我們可以通過判斷返回值是不是 0 來判斷當前是在父程序還是子程序中執行。
在 Python 中同樣提供了 fork() 函式,此函式位於 os 模組下。
例子:
import os
import time
ret = os.fork() #建立了一個子程序
if ret == 0: #子程序
while True:
print("-------1--------")
time.sleep(1)
else: #父程序
while True:
print("-------2--------")
time.sleep(1)
輸出結果為:
-------2--------
-------1--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
-------1--------
-------2--------
無限迴圈。。。。。。(注:子程序和父程序的執行順序不確定,即1和2輸出順序不一定,由作業系統的排程演算法確定)
注意:如果父程序結束,子程序也跟著結束
如程式:
import os
import time
ret = os.fork()
if ret == 0:
while True:
print("---1-----")
time .sleep(1)
else:
print("---2-----")
輸出結果為:
---2-----
---1-----
使用Process建立子程序
linux下可以使用fork建立子程序,但windows下不支援fork函式,但可以使用Process建立子程序
注意:與fork不同的是,主程序會等待Process子程序完成後結束。
Process語法結構如下:
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示這個程序例項所呼叫物件;
args:表示呼叫物件的位置引數元組;
kwargs:表示呼叫物件的關鍵字引數字典;
name:為當前程序例項的別名;
group:大多數情況下用不到;
Process類常用方法:
is_alive():判斷程序例項是否還在執行;
join([timeout]):是否等待程序例項執行結束,或等待多少秒;
start():啟動程序例項(建立子程序);
run():如果沒有給定target引數,對這個物件呼叫start()方法時,就將執行物件中的run()方法;
terminate():不管任務是否完成,立即終止;
Process類常用屬性:
name:當前程序例項別名,預設為Process-N,N為從1開始遞增的整數;
pid:當前程序例項的PID值;
from multiprocessing import Process
import time
import random
def test():
for i in range(1,5):
print("---%d---"%i)
time.sleep(1)
p = Process(target=test)
p.start() #讓這個程序開始執行test函式裡面的程式碼
p.join() #等程序p結束之後,才會繼續向下走
print("---main----")
輸出結果為:
---1---
---2---
---3---
---4---
---main----
程序池建立子程序
當需要建立的子程序數量不多時,可以直接利用multiprocessing中的Process動態成生多個程序,但如果是上百甚至上千個目標,手動的去建立程序的工作量巨大,此時就可以用到multiprocessing模組提供的Pool方法。
初始化Pool時,可以指定一個最大程序數,當有新的請求提交到Pool中時,如果池還沒有滿,那麼就會建立一個新的程序用來執行該請求;但如果池中的程序數已經達到指定的最大值,那麼該請求就會等待,直到池中有程序結束,才會建立新的程序來執行.
multiprocessing.Pool常用函式解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式呼叫func(並行執行,堵塞方式必須等待上一個程序退出才能執行下一個程序),args為傳遞給func的引數列表,kwds為傳遞給func的關鍵字引數列表;
apply(func[, args[, kwds]]):使用阻塞方式呼叫func
close():關閉Pool,使其不再接受新的任務;
terminate():不管任務是否完成,立即終止;
join():主程序阻塞,等待子程序的退出, 必須在close或terminate之後使用;
程式(非阻塞方式):
from multiprocessing import Pool
import os
import time
def worker(num):
for i in range(2):
print("===pid=%d===num=%d"%(os.getpid(), num))
time.sleep(1)
pool = Pool(3) #定義一個程序池,最大程序數3
for i in range(5):
print("---%d---"%i)
pool.apply_async(worker, [i,]) #使用非阻塞方式呼叫func(並行執行,堵塞方式必須
#等待上一個程序退出才能執行下一個程序)
print("---start----")
pool.close() #關閉程序池,關閉後pool不能再新增新的請求
pool.join() #等待pool中所有子程序執行完成,必須放在close語句之後
print("---end----")
輸出:
---0---
---1---
---2---
---3---
---4---
---start----
===pid=24958===num=0
===pid=24959===num=1
===pid=24960===num=2
===pid=24958===num=0
===pid=24960===num=2
===pid=24959===num=1
===pid=24960===num=3
===pid=24958===num=4
===pid=24960===num=3
===pid=24958===num=4
---end----
程式(阻塞方式):
from multiprocessing import Pool
import os
import time
def worker(num):
for i in range(2):
print("===pid=%d===num=%d"%(os.getpid(), num))
time.sleep(1)
pool = Pool(3) #定義一個程序池,最大程序數3
for i in range(5):
print("---%d---"%i)
pool.apply(worker, [i,]) #使用非阻塞方式呼叫func(並行執行,堵塞方式必須
#等待上一個程序退出才能執行下一個程序)
print("---start----")
pool.close() #關閉程序池,關閉後pool不能再新增新的請求
pool.join() #等待pool中所有子程序執行完成,必須放在close語句之後
print("---end----")
輸出:
---0---
===pid=24999===num=0
===pid=24999===num=0
---1---
===pid=25000===num=1
===pid=25000===num=1
---2---
===pid=25001===num=2
===pid=25001===num=2
---3---
===pid=24999===num=3
===pid=24999===num=3
---4---
===pid=25000===num=4
===pid=25000===num=4
---start----
---end----
注意:程序池和fork()一樣,不會等待子程式結束
例子:
from multiprocessing import Pool
import os
import time
def worker():
for i in range(2):
print("===pid=%d==="%os.getpid())
time.sleep(1)
pool = Pool(3) #定義一個程序池,最大程序數3
for i in range(5):
print("---%d---"%i)
pool.apply_async(worker) #使用非阻塞方式呼叫func(並行執行,堵塞方式必須
#等待上一個程序退出才能執行下一個程序)
輸出:
---0---
---1---
---2---
---3---
---4---