玩转python(2)多线程的历史2
線程這個概念早在多核CPU出現之前就提出來了,單核時代的多線程主要是為了讓CPU盡量不處于空閑狀態,使其計算能力始終能得到利用。但本質上講,在任意時刻只有一個線程在執行。
盡管任意時刻只有一個線程在執行,但是依然有些問題需要解決,其中最重要的就是線程安全。這個問題的來源很簡單,我之前說過,CPU對指令是一條一條執行的,不過要注意的是,高級語言中的一行代碼在匯編語言層面上,可能由多條匯編指令組成的。舉一個簡單的例子,在c語言中對某個變量做自增操作:
int a = 0; int add(){a += 1;return a; }不過變成匯編指令就不這么簡單了,其中實現自增的主要是這兩條指令(大部分指令省略):
movl a(%rip), %eaxaddl $1, %eax這里之所以在例子中使用全局變量,是因為線程安全和數據同步主要是針對全局變量這類可以共享的資源。上面的a(%rip)表示全局變量a的值,%eax是一個寄存器。第一條指令表示把a的值保存在eax寄存器中,第二條指令對eax中的值加上1。
我們來考慮一個情況:現在有兩個線程A,B,都要調用add()函數,那么a的預期值應該是2。如果線程A執行完第一條指令后,發生了上下文切換,此時eax寄存器的值是a的初始值0,CPU去執行線程B,線程B執行完畢后,把1返回給a(%rip),再恢復執行線程A,由于線程A不會再去執行第一條指令,因此eax寄存器的值不會被更新,依舊是0,線程A執行完畢后,把1返回給a(%rip)。最終,a(%rip)的值是1而不是2。
上面這種情況就是我們常說的數據不同步,或者線程不安全。對此,人們提出了很多方法,比如原子操作,互斥鎖等等,出發點主要是以下兩種:
現在回到python這門語言上。荷蘭人Guido van Rossum為了打發時間,于1989年發明了腳本語言python。和java類似,python源碼首先會被編譯成字節碼(python項目中的pyc文件),然后由解釋器進行解釋。類似于在高級語言和匯編語言之間還多了一層中間語言。
上圖中,一個python表達式可以由多個解釋器指令構成,一個解釋器指令又可以被分成多個匯編指令,這意味著一個解釋器指令可能在執行過程中被打斷,事實也確實是這樣,python的解釋器CPython并不是線程安全的。所以,為了保證線程安全,首先要做到讓一個解釋器指令能不受線程調度影響被執行完畢,對此python解釋器的開發者們搗鼓出了python全局解釋器鎖,簡稱GIL。GIL在任一時刻只允許運行一個線程,當一個線程執行時間達到閾值時,釋放GIL,這樣連線程調度也變得簡單了許多。
那么GIL是不是解決了線程安全的問題了呢?沒有。這是python中的一個深坑。下一篇博客我會寫一些自己在學習GIL時的心得。
轉載于:https://www.cnblogs.com/bugsheep/p/9008396.html
總結
以上是生活随笔為你收集整理的玩转python(2)多线程的历史2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于jQuery/zepto的单页应用(
- 下一篇: Python学习笔记——GIF倒放处理