1. 程式人生 > >python中多程序程式設計詳解

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之後使用;