python多執行緒的一點理解
理解這個其實需要懂一點作業系統的知識,不得不感嘆學科之間其實很多都是有聯絡的。
其實多執行緒就比如泡麵的時候一邊燒開水一邊放醬料,兩不耽誤。
在單核cpu中執行緒通過併發來實現cpu運算資源的高效使用
import time, threading # 新執行緒執行的程式碼: def loop(): print('thread %s is running...' % threading.current_thread().name) n = 0 while n < 5: n = n + 1 print('thread %s >>> %s' % (threading.current_thread().name, n)) time.sleep(1) print('thread %s ended.' % threading.current_thread().name) print('thread %s is running...' % threading.current_thread().name) t = threading.Thread(target=loop, name='LoopThread') t.start() t.join() print('thread %s ended.' % threading.current_thread().name)
在多核cpu中由於每個核心都能跑一個執行緒,所以n個核心的cpu就能並行(注意這裡是並行了不再是併發了)n個執行緒
但是當python在多核cpu中卻存在一定的效能缺陷,這裡我們試著多開幾個執行緒看看
import threading, multiprocessing def loop(): x = 0 while True: x = x ^ 1 if __name__=='__main__': for i in range(multiprocessing.cpu_count()): t = threading.Thread(target=loop) t.start()
這裡開了和cpu個數相等的執行緒,按道理來說1個執行緒的死迴圈可以跑滿1個核心,所有核心都跑一個迴圈cpu利用率肯定會爆炸吧
但是結果呢?
這裡就 涉及到了GIL(Global Interpreter Lock
)全域性直譯器鎖在我查了各種資料後得出的結果就是,GIL是很久以前的
大佬為了防止執行緒崩潰設定的執行緒保護措施,簡單來說 就是執行緒執行前先加一個全域性鎖,但這個鎖只有1個,所以不管你
幾個核心都只能同時跑1個執行緒這個鎖不是python的特性,是直譯器CPython的特性,像JPython就沒有這個東西。
當時市面上還沒有出現多核cpu,摩爾定律還沒有失效,所以在當時這個東西還是很好用的,但隨著技術進步這
個慢慢就成了python的累贅
來看解決辦法,我瞭解到的方法是通過多程序來實現,試驗了一下,確實有用
import threading, multiprocessing
from multiprocessing import Process
def loop():
x = 0
while True:
x = x ^ 1
if __name__=='__main__':
for i in range(multiprocessing.cpu_count()):
t = Process(target=loop)
t.start()
至於為什麼多程序可以實現,我在stackoverflow上看到的解答是,python為每個程序配一個直譯器,這樣下來
n個程序就有n個直譯器,每個程序一個主執行緒,GIL就加在這個主執行緒上,自然就突破了GIL的效能限制。
(至於更深入的原理可能需要等更加深入學習才能解釋出來)
這裡需要明確的是,雖然有GIL但是並不代表python的多執行緒就是雞肋,這個其實把我坑了有段時間,我一度以為python的多執行緒沒有用,但實際上多執行緒在解決IO密集型的任務上依舊有很大的優勢,畢竟人家就是為這個而生的。