python如何支援併發?

oaksharks發表於2020-07-25

由於GIL(Global Interpreter Lock)的存在使得在同一時刻Python程式只能使用CPU的一個核心,也就是對應作業系統的一個
核心執行緒,對於一個Python web程式,如果有個請求,並且都是長耗時的計算任務(佔用),這個程式在接受第一個請求後
還能處理別的請求麼?假如web程式接受到請求就while True了:

def handle_request(request):
    while True:
        pass

從程式碼上理解,Python只有一個真正的執行執行緒,程式碼走到while True就佔用唯一的一個cpu核心了,它還有機會處理
別的任務麼?

來啟動兩個執行緒都進行while True ,觀察他們是否都能執行來模擬那兩個請求:

import time, threading

def f1(name):
    while True:
        print(name)
        time.sleep(1)

threading.Thread(target=f1, args=('f1', )).start()
threading.Thread(target=f1, args=('f2', )).start()

輸出結果:

f1
f2
f2f1

f2
f1
...

實際上使用Django(一個Python Web 框架)測試,即使一個請求執行了while True這樣的程式碼,它還是可以處理別的請求(支援併發);

來解釋一下為什麼兩個while True 都能執行:
還是用GIL這把鎖,第一個while True的執行緒拿到這把鎖才能執行,然後它執行了一個print(name)接著把鎖釋放了,
它就暫停了,接著第二個while True執行緒拿到GIL後開始執行,圍繞GIL交替執行,就實現了Python的多執行緒。

總結一下:

while True也不能一直持有CPU資源,它也是執行一會歇一會,這就給了其他程式機會,這裡面有兩個關鍵點:

  1. 如何搶到這把鎖
  2. 如何釋放鎖

搶鎖,排隊。給lock安排一個佇列,想執行的進這個佇列。

釋放鎖的有點類似程式排程:

  • 劃分時間片(執行一樣的時間)
  • 執行指令計數(執行一樣的指令次數)
  • 碰到IO操作(被動等待)
  • 主動等待(wait/join/sleep)

碰到IO操作,需要等待IO裝置完成計算才能繼續執行執行緒,這段時間內不佔用CPU資源,先把鎖釋放了。
主動等待,典型的就是sleep,主動放棄鎖,等到一定時機再重新執行。

以上分析 說明Python支援併發,但是由於無法利用多核處理器優勢,對於大量併發下的計算密集型應用
不適合使用Python。

相關文章