1. 程式人生 > 程式設計 >Python 多程序、多執行緒效率對比

Python 多程序、多執行緒效率對比

Python 界有條不成文的準則: 計算密集型任務適合多程序,IO 密集型任務適合多執行緒。本篇來作個比較。

通常來說多執行緒相對於多程序有優勢,因為建立一個程序開銷比較大,然而因為在 python 中有 GIL 這把大鎖的存在,導致執行計算密集型任務時多執行緒實際只能是單執行緒。而且由於執行緒之間切換的開銷導致多執行緒往往比實際的單執行緒還要慢,所以在 python 中計算密集型任務通常使用多程序,因為各個程序有各自獨立的 GIL,互不干擾。

而在 IO 密集型任務中,CPU 時常處於等待狀態,作業系統需要頻繁與外界環境進行互動,如讀寫檔案,在網路間通訊等。在這期間 GIL 會被釋放,因而就可以使用真正的多執行緒。

以上是理論,下面做一個簡單的模擬測試: 大量計算用 math.sin() + math.cos() 來代替,IO 密集型用 time.sleep() 來模擬。 在 Python 中有多種方式可以實現多程序和多執行緒,這裡一併納入看看是否有效率差異:

  1. 多程序: joblib.multiprocessing,multiprocessing.Pool,multiprocessing.apply_async,concurrent.futures.ProcessPoolExecutor
  2. 多執行緒: joblib.threading,threading.Thread,concurrent.futures.ThreadPoolExecutor
from multiprocessing import Pool
from threading import Thread
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os,math
from joblib import Parallel,delayed,parallel_backend


def f_IO(a): # IO 密集型
 time.sleep(5)

def f_compute(a): # 計算密集型
 for _ in range(int(1e7)):
  math.sin(40) + math.cos(40)
 return

def normal(sub_f):
 for i in range(6):
  sub_f(i)
 return

def joblib_process(sub_f):
 with parallel_backend("multiprocessing",n_jobs=6):
  res = Parallel()(delayed(sub_f)(j) for j in range(6))
 return


def joblib_thread(sub_f):
 with parallel_backend('threading',n_jobs=6):
  res = Parallel()(delayed(sub_f)(j) for j in range(6))
 return

def mp(sub_f):
 with Pool(processes=6) as p:
  res = p.map(sub_f,list(range(6)))
 return

def asy(sub_f):
 with Pool(processes=6) as p:
  result = []
  for j in range(6):
   a = p.apply_async(sub_f,args=(j,))
   result.append(a)
  res = [j.get() for j in result]

def thread(sub_f):
 threads = []
 for j in range(6):
  t = Thread(target=sub_f,))
  threads.append(t)
  t.start()
 for t in threads:
  t.join()

def thread_pool(sub_f):
 with ThreadPoolExecutor(max_workers=6) as executor:
  res = [executor.submit(sub_f,j) for j in range(6)]

def process_pool(sub_f):
 with ProcessPoolExecutor(max_workers=6) as executor:
  res = executor.map(sub_f,list(range(6)))

def showtime(f,sub_f,name):
 start_time = time.time()
 f(sub_f)
 print("{} time: {:.4f}s".format(name,time.time() - start_time))

def main(sub_f):
 showtime(normal,"normal")
 print()
 print("------ 多程序 ------")
 showtime(joblib_process,"joblib multiprocess")
 showtime(mp,"pool")
 showtime(asy,"async")
 showtime(process_pool,"process_pool")
 print()
 print("----- 多執行緒 -----")
 showtime(joblib_thread,"joblib thread")
 showtime(thread,"thread")
 showtime(thread_pool,"thread_pool")


if __name__ == "__main__":
 print("----- 計算密集型 -----")
 sub_f = f_compute
 main(sub_f)
 print()
 print("----- IO 密集型 -----")
 sub_f = f_IO
 main(sub_f)

結果:

----- 計算密集型 -----
normal time: 15.1212s

------ 多程序 ------
joblib multiprocess time: 8.2421s
pool time: 8.5439s
async time: 8.3229s
process_pool time: 8.1722s

----- 多執行緒 -----
joblib thread time: 21.5191s
thread time: 21.3865s
thread_pool time: 22.5104s



----- IO 密集型 -----
normal time: 30.0305s

------ 多程序 ------
joblib multiprocess time: 5.0345s
pool time: 5.0188s
async time: 5.0256s
process_pool time: 5.0263s

----- 多執行緒 -----
joblib thread time: 5.0142s
thread time: 5.0055s
thread_pool time: 5.0064s

上面每一方法都統一建立6個程序/執行緒,結果是計算密集型任務中速度:多程序 > 單程序/執行緒 > 多執行緒, IO 密集型任務速度: 多執行緒 > 多程序 > 單程序/執行緒。

以上就是Python 多程序、多執行緒效率比較的詳細內容,更多關於Python 多程序、多執行緒的資料請關注我們其它相關文章!