二十四、深入Python多進程multiprocessing模組

@Author: Runsen

threading 包為 Python 提供了執行緒模型,而 multiprocessing 包則為另一種並發模型 — 多進程模型提供了強大的解決方案。

multiprocessing

multiprocessing包是Python中的多進程管理包。與之前的threading.Thread類似,它可以利用multiprocessing.Process對象來創建一個進程。

multiprocessing的模組的API非常簡單直觀,可以讓新手迅速上手在多個進程之間劃分工作。我們現在看一個官方簡單的例子:

# importing the multiprocessing module 
import multiprocessing 

def print_cube(num): 
    print("Cube: {}".format(num * num * num)) 

def print_square(num): 
    print("Square: {}".format(num * num)) 

if __name__ == "__main__": 
    # creating processes 
    p1 = multiprocessing.Process(target=print_square, args=(10, )) 
    p2 = multiprocessing.Process(target=print_cube, args=(10, )) 

    # starting process 1&2
    p1.start() 
    p2.start() 

    # wait until process 1&2 is finished 
    p1.join() 
    p2.join() 

    # both processes finished 
    print("Done!") 

運行結果是這樣的:

Square: 100
Cube: 1000
Done!

上面程式碼中導入了multiprocessing模組,隨後定義了兩個函數,它們的功能分別是列印一個數的三次方和列印一個數的平方。

之後關鍵的步驟來了,要創建多個進程,首先需要創建Process類的對象。在這個例子中Process類接收了兩個參數:

  • target:在進程中被執行的函數
  • args:向被執行函數傳遞的參數

執行緒池

ThreadPool類提供一個執行緒池,該執行緒池可用於發送工作項、處理非同步 I/O、代表其他執行緒等待以及處理計時器。

通常可導入模組:from multiprocessing import Pool

創建執行緒池:pool = Pool(10)

官方提供了比較常見的三種使用執行緒池的方法。分別是mapapplyapply_async

Map

其中map規定執行緒池執行的任務:result = pool.map(func,datalist)

func為所要執行的函數,datalist為參數列表,執行緒池也會依次在參數列表中提取參數帶入函數中來執行函數,參數列表的長度也就是執行緒池所要執行的任務數量。

# 進程池即創建一個進程庫,事先設置好需要多少進程,從進程庫中提取這些已創建的進程即可。
# Pool.map()
import multiprocessing

def test(i):
    print(i)

if __name__ == '__main__':
    list1 = list(range(5))  # 創建一個列表,map方法會用到
    pool1 = multiprocessing.Pool(processes=4)  # 創建一個進程池,這裡創建了含有4個進程的進程池
    pool1.map(test, list1)
    '''
    對pool1使用map方法,在這個例子中即形成(test(0),test(1),test(2),test(3),test(4) 這些任務)
    這些將執行的任務是按順序執行的,也就是說進程1執行test(0),進程2執行test(1),進程3執行test(2),
    進程4執行test(3),還多出一個任務則需要等待,等到某個進程提前結束了就再執行這個任務。
    這樣的話相當於一個進程執行一次單獨的任務,十分方便某些任務
    如果函數有返回值即return,還可以使用result = pool1.map(test,list1)獲取每個進程的返回值,
    但是這裡是所有返回值在一起,需要自己對其按需處理。
    '''
    pool1.close()  # close方法用於關閉進程池,即恢復到沒有子進程的情況
    pool1.join()

除了map方法,還有applyapply_async 方法用來執行進程,允許多個進程同時進入池子。

apply

multiprocessing模組中,apply阻塞主進程, 並且一個一個按順序地執行子進程, 等到全部子進程都執行完畢後 ,繼續執行 apply()後面主進程的程式碼。

import time
import multiprocessing

def doIt(num):
    print("Process num is : %s" % num)
    time.sleep(1)
    print('process  %s end' % num)

if __name__ == '__main__':
    print('mainProcess start')
    # 記錄一下開始執行的時間
    start_time = time.time()
    # 創建三個子進程
    pool = multiprocessing.Pool(3)
    print('Child start')
    for i in range(3):
        pool.apply(doIt, [i])
    print('mainProcess done time:%s s' % (time.time() - start_time))
    pool.close()
    pool.join()

輸出如下所示

mainProcess start
Child start
Process num is : 0
process  0 end
Process num is : 1
process  1 end
Process num is : 2
process  2 end
mainProcess done time:3.7142281532287598 s

執行結果 我們可以看到, 主進程開始執行之後, 創建的三個子進程也隨即開始執行, 主進程被阻塞, 而且接下來三個子進程是一個接一個按順序地執行, 等到子進程全部執行完畢之後, 主進程就會繼續執行, 列印出最後一句。

apply_async

接下來是使用apply_async(), 只需要把上面的程式碼使用 apply()的地方改成apply_async() 即可, 程式碼如下。

import time
import multiprocessing

def doIt(num):
    print("Process num is : %s" % num)
    time.sleep(1)
    print('process  %s end' % num)

if __name__ == '__main__':
    print('mainProcess start')
    # 記錄一下開始執行的時間
    start_time = time.time()
    # 創建三個子進程
    pool = multiprocessing.Pool(3)
    print('Child start')
    for i in range(3):
        pool.apply_async(doIt, [i])
    print('mainProcess done time:%s s' % (time.time() - start_time))
    pool.close()
    pool.join()

輸出如下所示

mainProcess start
Child start
mainProcess done time:0.060953378677368164 s
Process num is : 0
Process num is : 1
Process num is : 2
process  0 end
process  1 end
process  2 end

apply_async() 非阻塞非同步的, 他不會等待子進程執行完畢, 主進程會繼續執行, 他會根據系統調度來進行進程切換。

CPU在執行第一個子進程的時候, 還沒等第一個子進程結束, 系統調度到了按順序調度到了第二個子進程, 以此類推, 一直調度運行子進程, 一個接一個地結束子進程的運行, 最後運行主進程, 而且我們可以看到使用apply_async()的執行效力會更高, 你看一下他們各自執行結果最後一句的執行消耗時間就知道了, 這也是官方推薦我們使用apply_async()的主要原因吧

參考://docs.python.org/zh-cn/3.6/

今天也學到了很多東西呢,明天有什麼新知識呢?真期待鴨如果喜歡文章可以關注我哦

本文已收錄 GitHub,傳送門~ ,裡面更有大廠面試完整考點,歡迎 Star。

Tags: