前言
在Python中,計算密集型任務適用於多程式,IO密集型任務適用於多執行緒
正常來講,多執行緒要比多程式效率更高,因為程式間的切換需要的資源和開銷更大,而執行緒相對更小,但是我們使用的Python大多數的直譯器是Cpython,眾所周知Cpython有個GIL鎖,導致執行計算密集型
任務時多執行緒實際只能是單執行緒
,而且由於執行緒之間切換的開銷導致多執行緒往往比實際的單執行緒還要慢,所以在 python 中計算密集型任務通常使用多程式,因為各個程式有各自獨立的GIL,互不干擾。
而在IO密集型
任務中,CPU時常處於等待狀態,作業系統需要頻繁與外界環境進行互動,如讀寫檔案,在網路間通訊等。在這期間GIL會被釋放,因而就可以使用真正的多執行緒。
上面都是理論,接下來實戰看看實際效果是否符合理論
練習
"""多執行緒多程式模擬執行效率"""
from multiprocessing import Pool
from threading import Thread
import time, math
def simulation_IO(a):
"""模擬IO操作"""
time.sleep(3)
def simulation_compute(a):
"""模擬計算密集型任務"""
for i in range(int(1e7)):
math.sin(40) + math.cos(40)
return
def normal_func(func):
"""普通方法執行效率"""
for i in range(6):
func(i)
return
def mp(func):
"""程式池中的map方法"""
with Pool(processes=6) as p:
res = p.map(func, list(range(6)))
return
def asy(func):
"""程式池中的非同步執行"""
with Pool(processes=6) as p:
result = []
for j in range(6):
a = p.apply_async(func, args=(j, ))
result.append(a)
res = [j.get() for j in result]
def thread(func):
"""多執行緒方法"""
threads = []
for j in range(6):
t = Thread(target=func, args=(j, ))
threads.append(t)
t.start()
for t in threads:
t.join()
def showtime(f, func, name):
"""
計算並展示函式的執行時間
:param f: 多程式和多執行緒的方法
:param func: 多程式和多執行緒方法中需要傳入的函式
:param name: 方法的名字
:return:
"""
start_time = time.time()
f(func)
print(f"{name} time: {time.time() - start_time:.4f}s")
def main(func):
"""
執行程式的主函式
:param func: 傳入需要計算時間的函式名
"""
showtime(normal_func, func, "normal")
print()
print("------ 多程式 ------")
showtime(mp, func, "map")
showtime(asy, func, "async")
print()
print("----- 多執行緒 -----")
showtime(thread, func, "thread")
if __name__ == "__main__":
print("------------ 計算密集型 ------------")
func = simulation_compute
main(func)
print()
print()
print()
print("------------ IO 密集型 ------------")
func = simulation_IO
main(func)
結果
線性執行 | 多程式(map) | 多程式(async) | 多執行緒 | |
---|---|---|---|---|
計算密集型 | 16.0284s | 3.5236s | 3.4367s | 15.2142s |
IO密集型 | 18.0201s | 3.0945s | 3.0809s | 3.0041s |
結論
從表格中很明顯的可以看出:
- 計算密集型任務的速度:多程式 >多執行緒> 單程式/執行緒
- IO密集型任務速度: 多執行緒 > 多程式 > 單程式/執行緒。
所以,針對計算密集型任務使用多程式,針對IO密集型任務使用多執行緒