python中多程序程式設計詳解
由於個人知識面有限,以下就說說我對python中多程序程式設計的理解,如果有錯誤的地方,請多多指教。
在python中有三種方式建立多程序:fork,process,pool
一: fork應用
import os
import time
print("只有主程序執行此語句")
#呼叫fork函式後,會產生2個值:子程序的pid和父程序的pid,
# 其中子程序的pid為0,父程序的pid為子程序的pid,其實就相當於返回了2個子程序號
#以下為os模組中fork函式的解釋
#1.Fork a child process.
#2.Return 0 to child process and PID of child to parent process.
pid = os.fork() #呼叫os模組的fork函式建立程序
print("主程序和子程序都能執行此語句,程序id==%d"%os.getpid())
if pid == 0:
#子程序執行程式碼塊
print("我是子程序,子程序id是%d,父程序id是%d"%(os.getpid(),os.getppid()))
elif pid > 0:
#父程序執行的程式碼塊
#下句語句中的pid容易跟if判斷中的pid混淆
print("我是父程序,父程序id是%d,子程序id是%d"%(os.getpid(),pid))
os.getpid() 獲取當前程序id
os.getppid() 獲取父程序id
注意:1: fork函式只能在unix中執行。
2: 父程序和子程序執行沒有先後順序,執行順序由系統根據相關規則呼叫。
3: 主程序不會等所有子程序結束後而結束。
二: process應用
由於window無法呼叫fork函式,如果要在window建立多程序,則需要用到multiprocessing模組,而multiprocessing模組就是跨平臺版本的多程序模組。
from multiprocessing import Process
import time
def test():
while True:
print("1-----我是子程序" )
time.sleep(2)
p = Process(target=test)
p.start()
while True:
print("2----我是主程序")
time.sleep(2)
上處程式碼為使用Process類建立的例項
from multiprocessing import Process
import time
import os
def test1(interval):
start = time.time()
time.sleep(interval)
print("我是test1,我的程序號是%d,我的父程序id是%d"%(os.getpid(),os.getppid()))
end = time.time()
def test2(interval):
start = time.time()
time.sleep(interval)
print("我是test2,我的程序號是%d,我的父程序id是%d"%(os.getpid(),os.getppid()))
end = time.time()
p1 = Process(target=test1,args=(5,))
p1.start()
print("p1.pid = %d"%p1.pid)
p1.join()
p2 = Process(target=test2,args=(1,))
p2.start()
print("p2.pid = %d"%p2.pid)
上段程式碼中的join是指阻塞程序,當所有的物件程序都結束後其他程序才可繼續向下執行程式。
此外: join函式可以加阻塞時間,如果加上時間,則表示阻塞系統指定時間,如p1.join(2),到達指定時間後,如果子程序沒有結束,那麼主程序可以和子程序同時執行。如果不指定阻塞時間,則表示等待物件程序執行完畢後,主程序才可繼續向下執行。
注意:主程序會等待子程序的結束而結束
下面將介紹Process類中常用方法和屬性
常用屬性:
target:表示這個程序例項所呼叫物件;
args:表示呼叫物件的位置引數元組;
kwargs:表示呼叫物件的關鍵字引數字典;
pid:當前程序例項的PID值;
常用方法:
start() 建立程序例項同時並啟動程序
is_alive():判斷程序例項是否還在執行;
join([timeout]):是否等待程序例項執行結束,或等待多少秒
terminate():不管任務是否完成,立即終止
run():如果沒有給定target引數,對這個物件呼叫start()方法時,就將執行物件中的run()方法,一般用於繼承Process類中重寫run方法
重寫run方法案例如下:
from multiprocessing import Process
import time
start = time.time()
class MyProcess(Process):
def __init__(self,num):
super().__init__()
self.num = num
def run(self):
start = time.time()
print("子程序開始執行")
time.sleep(self.num)
end = time.time()
print("子程序執行時間是%#.5f"%(end-start))
myProcess = MyProcess(2)
myProcess.start()
# myProcess.run()
# myProcess.join()
end = time.time()
print("主程序執行時間是%#.5f"%(end-start))
三: pool應用
使用場景和使用原理:
當需要建立的子程序數量不多時,可以直接利用multiprocessing中的Process動態成生多個程序,但如果是上百甚至上千個目標,手動的去建立程序的工作量巨大,此時就可以用到multiprocessing模組提供的Pool方法。初始化Pool時,可以指定一個最大程序數,當有新的請求提交到Pool中時,如果池還沒有滿,那麼就會建立一個新的程序用來執行該請求;但如果池中的程序數已經達到指定的最大值,那麼該請求就會等待,直到池中有程序結束,才會建立新的程序來執行。
Pool分為兩種:apply_async 非阻塞式和apply 阻塞式
下面將這兩種使用方法和區別進行介紹
apply_async 非阻塞式,以下是案例:
from multiprocessing import Pool
import time
import os
import random
start = time.time()
def work(num):
start = time.time()
time.sleep(random.random()*2)
end = time.time()
print("%d執行的程序id是%d,父程序id是%d,執行時間是%#.5f"%(num,os.getpid(),os.getppid(),(end-start)))
pool = Pool(3)
for i in range(0,10):
# pool.apply_async(work,args=(i,)) #非阻塞式
pool.apply(work, args=(i,)) #阻塞式
pool.close()
# pool.join()
#使用非阻塞式時開啟下面for迴圈
#for j in range(0,12):
# time.sleep(random.random()*2)
# print("主程序的pid是%d,j==%d"%(os.getpid(),j))
end = time.time()
print("主程序的id是%d,執行時間是%d"%(os.getpid(),(end-start)))
當使用非堵塞式時,主程序和子程序同時執行,並且主程序不會等待子程序的結束而結束。
當使用堵塞式時,系統會等待一個程序結束之後在執行其他程序。這類似與單程序。
multiprocessing.Pool常用函式解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式呼叫func(並行執行,堵塞方式必須等待上一個程序退出才能執行下一個程序),args為傳遞給func的引數列表,kwds為傳遞給func的關鍵字引數列表;
apply(func[, args[, kwds]]):使用阻塞方式呼叫func
close():關閉Pool,使其不再接受新的任務;
terminate():不管任務是否完成,立即終止;
join():主程序阻塞,等待子程序的退出, 必須在close或terminate之後使用;