天天看點

Python 多程序程式設計 ThreadPoolExecutor, multiprocessing

一、并發與并行的差別

  1. 并發:一個時間段内,有幾個程式在同一個CPU上運作,但是任意時刻隻有一個程式在CPU上運作。
  2. 并行:并行是指任意時刻上,有多個程式同時運作在多個CPU上所有常說高并發,沒有說高并行,因為CPU數量是有限的。

二、多程序與多線程的差別

  1. 對于耗 CPU 的操作,用多程序優于多線程,因為有 GIL 鎖,不會常釋放,耗 CPU 操作無法使用多線程。
  2. 多 IO 操作,常會釋放 GIL,是以可以多使用多線程。

三、多程序程式設計

1. 使用 fork()  方法建立子程序(fork隻能用于linux/unix中)。

import os

# fork隻能用于linux/unix中
pid = os.fork()
print("bobby")
if pid == 0:    # 子程序運作這段
  print('子程序 {} ,父程序是: {}.' .format(os.getpid(), os.getppid()))
else:    # 父程序運作這段
  print('我是父程序:{}.'.format(pid))

"""
在 linux 下運作後,會列印:
bobby
我是父程序: 24474
bobby
子程序 24474, 父程序是:24473
"""
           

fork() 方法建立一個子程序,子程序會将父程序裡的資料、代碼原樣拷貝到子程序當中,父程序依然會向下運作,父子程序都從 fork() 的地方繼向下運作。

2. 使用 ProcessPoolExecutor 進行多程序程式設計。

from concurrent.futures import ProcessPoolExecutor
           

ProcessPoolExecutor 接口跟  ThreadPoolExecutor 的 api 幾乎一模一樣,具體使用方法可以參照上一篇部落格:python線程池 ThreadPoolExecutor 使用詳解

3. 使用 multiprocessing 子產品進行多程序程式設計。

(1)multiprocessing.Process

import multiprocessing as mp
threads = []
for i in path:
  threads.append(mp.Process(target=md5sum,args=(i,)))
#建立一個multiprocessing.process.Process對象
#執行
for m in threads:
  m.start()
#回收
for m in threads:
  m.join()
           

(2)使用線程池 multiprocessing.Pool()

def test():
  pass

# 建立一個multiprocessing.pool.Pool的對象
p1 = mp.Pool(processes =5)

#向程序池裡添加任務
result = pool.apply_async(test, args=(3,))

# 關閉程序池,阻止更多的任務送出到程序池Pool,待任務完成後,工作程序會退出
p1.close()

# 結束工作程序,不再處理未完成的任務
# p.terminate() 

# 等待工作線程的退出,必須在close()或terminate()之後使用,因被終止的程序需要被父程序調用wait(join等價于wait),否則程序會成為僵屍程序。
p1.join()

print(result.get())
           

(a) Pool裡有兩種添加子程序的方法:

  • apply_async 異步添加
  • p1.apply(test) 阻塞式添加,逐漸執行,相當于單程序

(b) 當Pool所有的程序任務完成後,會産生5個僵屍程序,如果主線程不結束,系統不會自動回收資源,需要調用join函數去回收。

(c) map() 方法:它融合了map函數和apply_async()函數的功能

(d) p.close():關閉程序池,阻止更多的任務送出到程序池Pool,待任務完成後,工作程序會退出

(e) p.terminate():結束工作程序,不再處理未完成的任務

(f) p.join():等待工作線程的退出,必須在close()或terminate()之後使用,因被終止的程序需要被父程序調用wait(join等價于wait),否則程序會成為僵屍程序。

參考文章: [Python]multiprocessing

繼續閱讀