2021年11月16日 星期二

[Python] Threading (1):什麼是多執行緒Multithreading

 

多執行緒(multithreading)技術能讓程序(process)運行多個執行緒(thread)達到平行執行,透過平行執行我們能更快得到計算結果。


在Python裡或許大家或多或少都有聽過,Python的multithreading並不能真的達成平行運行,實際同一時間下只有一個thread在運作。


這裡可以想像一個process就像是一座工廠,process工廠裡有各種機器資源備好等著被使用(即memory, registers, stack...等系統資源),而這process工廠裡一開始起碼有一人員工作事,但當事情多時,顯然你會覺得人手不足,於是你導入多執行緒技術讓你的程式運行多個thread,開一個thread就相當於多找一個員工到這工廠裡做工,thread員工們可以共享使用process工廠裡的資源,這比起多建一個工廠要省資源。


進入正題,為什麼說Python的多執行緒不能做到真的平行?

套用上述的例子,python process工廠裡其實有一個每個thread員工做工都需要的資源,但很不幸的一個工廠裡就只有一個,這資源就是「全局解釋器鎖」(GIL, Global Intepreter Lock),thread沒拿到這個鎖前都是不允許運行,因此才會說在Python裡的multithread沒有真正的平行。至於為什麼有這個鎖的設計,詳情請自行google,我自己的認知是python底層的限制,在沒有鎖的設計會發生各種不預期的錯誤,所以才導入全域鎖增加穩定性。


大概這時有人就會想說這樣我請再多個員工也沒用吧,因為同時只能有一個員工作事,不就跟只有一個員工時的狀況一樣。

的確python的multithread沒有理想上的多人同時做工的效果,但在下面這樣的狀況下,多個員工還是有能加快整體效率的機會,例如現在有個任務是要煮中餐,員工A負責單號員工的中餐,員工B則負責雙號員工的中餐,員工A在等煮湯的時間是需要等待的,在等待時間員工A其實就可以釋放GIL給員工B做事,像這樣的狀況下只有一個員工就只能乖乖等完湯滾的這段時間再接著做事就比較花時間。


或許有人就又會想,一個員工也行吧,那個員工聰明一點的話,就會在等待的時間去找別的事做,還可以省去交接給別的員工的時間之類的,這樣說是沒錯啦,但thread員工沒這麼聰明,他們只會接一個寫好完整步驟的工作,就是你寫的code要告訴他們任務內容,這任務通常就是執行某一個function,所以如果你告訴這員工任務煮湯,他就會等湯煮完在下一步。

不過在python 3.5後有了asynio,上述故事有了一點改變,那就是你可以在你的code裡先跟這個員工說好,煮湯這個步驟可以不用等,你可以先去做別的事,但這又是另一段很長的說明了,此章主要是想講multithread,這裡就不再繼續延伸。



那如果Python想做到真的平行呢?

那就必須要再建一個process工廠了,也就是做到multiprocessing,每個工廠裡都有一個自己的GIL,不過缺點你大可想像得到這比雇用多一個員工還要來得耗資源就是了。


下一章:[Python] Multithreading (2):Hello Thread 建立第一個 Multithread 程式




沒有留言:

張貼留言