[ Python - 11 ] 多線程及GIL全局鎖


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鎖,互不影響。

    但是,由於進程之間是獨立的存在,所以進程間通信就需要通過隊列的方式來實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM