實際上,不是,每個線程都是這個解釋器的新線程。
它是由OS,而不是內部管理只是Python的虛擬機中的Python代碼線程管理一個真正的線程。
需要GIL來防止非常基於OS的線程搞亂Python對象。
想象一個CPU上的一個線程和另一個CPU上的另一個線程。純平行線程,用匯編寫成。兩者同時嘗試更改註冊表值。根本不可取的情況。訪問相同內存位置的彙編指令最終會擾亂什麼地點以及何時移動。最後,這種行爲的結果可能很容易導致分段錯誤。那麼,如果我們用C語言編寫,C就控制這個部分,所以這不會發生在C代碼中。 GIL對C級別的Python代碼也一樣。因此,實現Python對象的代碼在更改它們時不會失去其原子性。想象一下,一個線程將一個值插入到另一個線程中正在向下移動的列表中,因爲另一個線程從中移除了一些元素。沒有GIL就會崩潰。
GIL對線程內的代碼的原子性沒有任何影響。它僅用於內部內存管理。
即使你有線程安全的對象,如雙端隊列(),如果你是在一次就可以了,無需額外的鎖做一個以上的操作,就可以得到在兩者之間插入另一個線程導致。和哎呀,問題發生!
咱們說一個線程需要的對象從堆棧,檢查一下東西,如果條件是正確刪除。
stack = [2,3,4,5,6,7,8]
def thread1():
while 1:
v = stack[0]
sleep(0.001)
if v%2==0: del stack[0]
sleep(0.001)
當然,這是愚蠢的,並應與stack.pop(0)來進行,以避免這種情況。但這是一個例子。
然後讓另一個線程將每個0添加到堆棧。002秒:
def thread2():
while 1:
stack.insert(0, stack[-1]+1)
sleep(0.002)
現在,如果你這樣做:
thread(thread2,())
sleep(1)
thread(thread1,())
會有一個時刻,儘管這不太可能,其中線程2()嘗試線程1之間恰好疊加了新的項目()的檢索和刪除。因此,thread1()將刪除一個新添加的項目,而不是正在檢查的項目。結果不符合我們的意願。所以,GIL不會控制我們在我們的線程中做什麼,只是線程正在做什麼 - 對於更基本的意義上的其他線程。
想象一下,你寫了一個服務器來購買一些事件的票。兩個用戶連接並嘗試同時購買同一張票。如果你不小心,用戶可能會結束坐在另一個之上。
線程安全的對象是執行操作的對象,它不允許直到第一個完成的另一個動作發生。例如,如果您在一個線程中迭代deque(),並在另一個線程的中間另一個線程嘗試追加某些內容,append()將會阻塞,直到第一個線程完成迭代爲止。這是線程安全的。
某些操作需要多個指令進行同步,其中的Python之間可以通過不同的線程來解釋。 GIL永遠不會*同步Python程序,與asyncio無關。 - 它只是確保Python對象在C級別上是線程安全的,而不是在Python級別上。 –