1. GIL
熟悉python的都知道,在C語言寫的python解釋器中存在全局解釋器鎖,由於全局解釋器鎖的存在,在同一時間內,python解釋器只能運行一個線程的代碼,這大大影響了python多線程的性能。而這個解釋器鎖由於歷史原因,現在幾乎無法消除。
python GIL 之所以會影響多線程等性能,是因為在多線程的情況下,只有當線程獲得了一個全局鎖的時候,那麼該線程的代碼才能運行,而全局鎖只有一個,所以使用python多線程,在同一時刻也只有一個線程在運行,因此在即使在多核的情況下也只能發揮出單核的性能。
2. 多線程處理IO密集型任務
IO密集型任務指的是系統的CPU性能相對硬碟、內存要好很多,此時,系統運作,大部分的狀況是CPU在等I/O (硬碟/內存) 的讀/寫操作,此時CPU Loading並不高。涉及到網絡、磁碟IO的任務都是IO密集型任務。一個線程執行IO密集型任務的時候,CPU處於閒置狀態,因此GIL會被釋放給其他線程,從而縮短了總體的等待運行時間。
from concurrent.futures import ThreadPoolExecutor
from time import sleep, time
# Worker數量
N = 4
# 建立線程池
pool = ThreadPoolExecutor(max_workers=N)2.1 定義一個IO密集型函數
該函數會「睡眠」x秒。
def io_bound_func(x):
sleep(x)
print("Sleep for %d seconds." % x)2.2 使用串行的方式處理
遍歷一個列表的所有元素,執行func函數。
def process_array(arr):
for x in arr:
io_bound_func(x)2.3 使用多線程處理
通過線程池的map方法,可以將同一個函數作用在列表中的所有元素上。
def fast_process_array(arr):
for x in pool.map(io_bound_func, arr):
pass2.4 計算函數運行時間
串行版本的運行時間 = 1 + 2 + 3 = 6秒多線程版本的運行時間 = max(1, 2, 3) = 3秒def time_it(fn, *args):
start = time()
fn(*args)
print("%s版本的運行時間為 %.5f 秒!" % (fn.__name__, time() - start))
time_it(process_array, [1, 2, 3])Sleep for 1 seconds.
Sleep for 2 seconds.
Sleep for 3 seconds.
process_array版本的運行時間為 6.00883 秒!time_it(fast_process_array, [1, 2, 3])Sleep for 1 seconds.
Sleep for 2 seconds.
Sleep for 3 seconds.
fast_process_array版本的運行時間為 3.00300 秒!3. 多線程CPU密集型任務
CPU密集型任務的特點是要進行大量的計算,消耗CPU資源,比如計算圓周率、對視頻進行高清解碼等等,全靠CPU的運算能力。一個線程執行CPU密集型任務的時候,CPU處於忙碌狀態,運行1000個字節碼之後GIL會被釋放給其他線程,加上切換線程的時間有可能會比串行代碼更慢。
3.1 定義一個CPU密集型函數
該函數會對[1, x]之間的整數進行求和。
def cpu_bound_func(x):
tot = 0
a = 1
while a <= x:
tot += x
a += 1
print("Finish sum from 1 to %d!" % x)
return tot3.2 使用串行的方式處理
遍歷一個列表的所有元素,執行func函數。
def process_array(arr):
for x in arr:
cpu_bound_func(x)3.3 使用多線程處理
通過線程池的map方法,可以將同一個函數作用在列表中的所有元素上。
def fast_process_array(arr):
for x in pool.map(cpu_bound_func, arr):
pass3.4 計算函數運行時間
def time_it(fn, *args):
start = time()
fn(*args)
print("%s版本的運行時間為 %.5f 秒!" % (fn.__name__, time() - start))
time_it(process_array, [10**7, 10**7, 10**7])Finish sum from 1 to 10000000!
Finish sum from 1 to 10000000!
Finish sum from 1 to 10000000!
process_array版本的運行時間為 2.10489 秒!time_it(fast_process_array, [10**7, 10**7, 10**7])Finish sum from 1 to 10000000!
Finish sum from 1 to 10000000!
Finish sum from 1 to 10000000!
fast_process_array版本的運行時間為 2.20897 秒!參考文章
1、Python中的GIL鎖:https://www.jianshu.com/p/c75ed8a6e9af
2、什麼是CPU密集型、IO密集型?:https://www.cnblogs.com/tusheng/articles/10630662.html