Python多進程學習(一)

前情:這裏只是單純介紹 Python 中的多進程的程序開發,詳細的內容還須要看操做系統知識。
複製代碼

fork()

  • 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

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.
子進程結束.
複製代碼

進程池 Pool

若是要啓動大量的子進程,能夠用進程池建立大量的子進程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 模塊包裝了底層的機制,提供了 QueuePipes 等多種方式來交換數據。

實戰

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…

但願看客老爺打賞些喝茶錢

支付寶

支付寶

微信

微信
相關文章
相關標籤/搜索