1. GIL是什么?
首先需要明確的一點是GIL並不是python的特性, 它是在實現python解析器(Cpython)時所引入的一個概念。
而Cpython是大部分環境下默認的python執行環境,要明確一點:GIL並不是python的特性,python完全可以不依賴於GIL。
2. 為什么會有GIL?
為了更有效的利用多核處理器的性能,就出現了多線程的編程方式,而隨之帶來的就是線程間數據的一致性和狀態同步的完整性
(例如:線程2需要線程1執行完成的結果,然而線程2又比線程1代碼量少,線程2執行完成,線程1仍然還在執行,這就是數據的同步性)
python為了利用多核,開始支持多線程,而解決多線程之間數據完整性和狀態同步最簡單的方式就是加鎖。
3. GIL的影響
GIL無疑就是一把全局排它鎖,全局鎖的存在會對多線程的效率有不小的影響。甚至就幾乎等於python是個單線程的程序。
下面通過實例來測試python單線程和多線程:
win7 python3.0+
#!_*_coding:utf-8_*_
# Author: hkey
import threading, time
def run_thread():
n = 0
while n <= 100000000:
n += 1
def single_run():
start_time = time.time()
for i in range(4):
t = threading.Thread(target=run_thread,)
t.start()
t.join() # 四個線程串行執行
print('single thread times:', time.time()-start_time)
def multi_run():
thread_list = []
start_time = time.time()
for i in range(4):
t = threading.Thread(target=run_thread,)
t.start()
thread_list.append(t)
for t in thread_list:
t.join() # 四個線程並行執行
print('multi threads times:', time.time()-start_time)
if __name__ == '__main__':
single_run()
multi_run()
# 線程的串行和並行是通過join()方法來確定的,join方法是阻塞當前線程並等待正在執行的子線程執行完畢。
執行結果:
single thread times: 28.13599991798401
multi threads times: 29.76200008392334
通過結果可以發現,單線程串行執行效率和多線程並發相比要快,這也證明了GIL全局鎖的存在
4. python多線程並行執行原理
在雙核cpu主機上,兩個線程均為CPU密集型運算線程,這里假設每個線程單獨占用一核cpu,因為GIL鎖的緣故,
同一時間片就只能有一個線程獲得GIL全局鎖,而另一個占用cpu的線程則無法執行,繼續等待,cpu時間就白白浪費掉,
也就是只有獲得GIL鎖的線程才能真正在cpu上運行。所以,多線程在python中只能交替執行,即使100個線程跑在100核cpu上,也只能用到1核。
5. 如何避免受到GIL的影響
既然python的多線程在多核主機上這么雞肋,那有什么更好的方式實現多並發嗎?
用進程+協程 代替 多線程的方式
在多進程中,由於每個進程都是獨立的存在,所以每個進程內的線程都擁有獨立的GIL鎖,互不影響。
但是,由於進程之間是獨立的存在,所以進程間通信就需要通過隊列的方式來實現。
