前情:這裏只是單純介紹 Python 中的多進程的程序開發,詳細的內容還須要看操做系統知識。
複製代碼
Python 的 os 模塊封裝了常見的系統調用,其中就包括 fork() ,能夠在 Python 程序中輕鬆建立子進程,實現多進程。php
Unix/Linux 操做系統(好比常見的 Mac 咯)提供了一個 fork() 系統調用,它被調用一次,返回兩次,由於操做系統自動把當前進程(稱爲父進程)複製了一份(稱爲子進程),而後分別在父進程和子進程內返回。ios
子進程永遠返回0,而父進程返回子進程的 ID,由於一個父進程能夠 fork 出不少子進程,因此父進程要記下每一個子進程的 ID,而子進程只須要調用 getppid() 就能夠拿到父進程的 ID。服務器
實戰(Python3環境)微信
import os
print("正在運行的進程是 %s ..." % os.getpid())
pid = os.fork() # 若是是子進程返回0,而父進程返回子進程的ID,有了fork調用,一個進程在接到新任務時就能夠複製出一個子進程來處理新任務,常見的Apache服務器就是由父進程監聽端口,每當有新的http請求時,就fork出子進程來處理新的http請求。
print("\rpid 是 %s" %pid)
if pid == 0:
print("子進程是 %s 和父進程是 %s." % (os.getpid(), os.getppid()))
else:
print("在父進程 %s 中建立了子進程 %s." % (os.getpid(), pid))
複製代碼
運行結果:app
正在運行的進程是 42322 ...
pid 是 46501
在父進程 42322 中建立了子進程 46501.
pid 是 0
子進程是 46501 和父進程是 42322.
複製代碼
multiprocessing 模塊是跨平臺版本的多進程模塊。它提供了一個 Process 類來表明一個進程對象。因此無論在 Unix/Linux 操做系統,仍是 Windows 操做系統,均可以用 Python 編寫多進程的程序。dom
實戰yii
from multiprocessing import Process
import os
# 子進程要執行的代碼
def my_proc(name):
print("運行子進程 %s." % (os.getpid()))
# 至關於程序執行入口
if __name__=='__main__':
print("父進程 %s." %os.getpid())
p = Process(target=my_proc, args=('test',)) # 傳入須要執行的函數和函數須要的參數,用start()啓動,這種方式比fork()更簡單
print("子進程將要開始.")
p.start()
p.join() # join() 能夠等待子進程結束後繼續往下執行,一般用於進程間同步
print("子進程結束.")
複製代碼
運行結果:async
父進程 42322.
子進程將要開始.
運行子進程 46580.
子進程結束.
複製代碼
若是要啓動大量的子進程,能夠用進程池建立大量的子進程svg
實戰函數
from multiprocessing import Pool
import os, time, random
def task(name):
print("運行任務 %s (%s)" %(name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print("任務 %s 耗時 %.2f 秒" %(name, (end-start)))
if __name__ == "__main__":
print("父進程 %s" %(os.getpid()))
p = Pool(6)
for i in range(10):
p.apply_async(task, args=(i,))
p.close()
print("等待全部子進程完畢")
p.join() # 對 Pool 對象調用 join() 方法會等待全部子進程執行完畢,調用 join() 以前必須先調用 close() ,調用 close() 以後就不能繼續添加新的 Process 了
print("全部子進程執行完畢")
複製代碼
運行結果:
父進程 42322
運行任務 2 (43382)
運行任務 1 (43381)
運行任務 3 (43383)
運行任務 0 (43380)
運行任務 4 (43384)
運行任務 5 (43385)
任務 4 耗時 0.05 秒
運行任務 6 (43384)
等待全部子進程完畢
任務 5 耗時 0.26 秒
運行任務 7 (43385)
任務 1 耗時 0.57 秒
運行任務 8 (43381)
任務 7 耗時 0.96 秒
運行任務 9 (43385)
任務 8 耗時 1.03 秒
任務 3 耗時 2.00 秒
任務 0 耗時 2.07 秒
任務 6 耗時 2.26 秒
任務 2 耗時 2.70 秒
任務 9 耗時 2.61 秒
全部子進程執行完畢
複製代碼
任務 2,1,3,0,4,5是馬上執行的,而其餘任務要等待前面某個任務完成後才執行,這是由於 Pool 的大小設置爲6,所以,最多同時執行6個進程,Pool 的默認大小是 CPU 的核數。
不少時候,子進程並非自身,而是一個外部進程。咱們建立了子進程後,還須要控制子進程的輸入和輸出。subprocess 模塊可讓咱們很是方便地啓動一個子進程,而後控制其輸入和輸出。
Process 之間確定是須要通訊的,操做系統提供了不少機制來實現進程間的通訊。Python 的 multiprocessing 模塊包裝了底層的機制,提供了 Queue、Pipes 等多種方式來交換數據。
實戰
from multiprocessing import Process, Queue
import os, time, random
# 往 queue 裏寫內容
def write(q):
print("寫內容的進程: %s" %os.getpid())
for v in 'ABC':
print("把 %s 寫進隊列..." %v)
q.put(v)
time.sleep(random.random())
# 從 queue 裏讀內容
def read(q):
print("讀內容的進程: %s" %os.getpid())
while True:
v = q.get(True)
print("從隊列中讀 %s." %v)
if __name__=="__main__":
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
pw.start()
pr.start()
pw.join() # 等待 pw 結束:
pr.terminate() # pr 進程裏是死循環,只能強行終止
複製代碼
運行結果:
寫內容的進程: 46049
讀內容的進程: 46050
把 A 寫進隊列...
從隊列中讀 A.
把 B 寫進隊列...
從隊列中讀 B.
把 C 寫進隊列...
從隊列中讀 C.
複製代碼
本文參考(不分前後順序):
廖雪峯的官方網站:www.liaoxuefeng.com/wiki/101695…
但願看客老爺打賞些喝茶錢