該文章參考了http://www.liaoxuefeng.com/wi... 廖雪峯的教程。python
一個進程至少有一個線程。
Python也提供多線程支持,並且Python中的線程並不是是模擬出來的多線程,而是系統級別的Posix Thread.git
Python標準庫提供了兩個模塊thread
和threading
。前者是低級庫,後者是高級庫。高級庫是對低級庫的封裝。
一般狀況下,咱們只須要使用threading
高級庫就能夠了。github
咱們只須要建立threading.Thread
類,並傳入一個須要線程執行的函數做爲target便可。編程
import threading import time def loop(): count = 1 while count < 4: print "Hello" time.sleep(1) count += 1 if __name__ == '__main__': thread = threading.Thread(target=loop, name="LoopThread") thread.start() thread.join() current_thread = threading.current_thread() print current_thread.getName() print "LoopThread Ended"
上述代碼主進程默認會建立一個主線程。
上面的代碼中,咱們用到了多個函數。多線程
join()
函數:即讓主線程序等待子線程完成後繼續。函數
current_thread()
函數:獲取當前線程的實例。oop
同一個變量,進程會拷貝一份存於各個進程中,互不影響。
同一個變量,線程則會互相共享。這就會帶來一些問題。由於cpu對線程是隨意切換的。那麼若是一個線程對某一個變量進行多步cpu操做的時候,若是不加鎖,那麼可能會在線程進行到一半的時候,會被切換到其餘線程,從而使得操做變亂。
一個典型的例子是「一存一取」的場景。
例如多個線程對銀行中的某一個帳戶進行操做。一個線程須要對帳戶進行一存一取某一個金額的操做纔會讓帳戶平衡。
可是多個線程對該帳戶進行操做的時候,且它們操做的金額常常是不同的,那麼最終的帳戶極可能是不平衡的。ui
thread 1: -100 thread 1: +100 thread 1: -100 thread 1: +100 thread 2: -200 thread 2: +200 thread 2: -200 thread 2: +200
上述描述了兩個線程按順序互補干擾地對某一個帳戶進行操做。
可是實際狀況是cpu隨意切換線程。上述操做是打亂的,例如操作系統
thread 1: -100 thread 2: -200 thread 2: +200 ...
此時,咱們發現帳戶並非平衡的。
若是解決呢?咱們須要對每個thread的一存一取操做加一把鎖。即改帳戶變量必須是讓一個線程先進行完整的一存一取操做後,才能被其餘線程所操做。.net
咱們能夠將要上鎖的代碼包裹起來,即:
lock.acquire() num = num + n num = num - n print num lock.release()
固然,lock能夠對資源的獲取和釋放,那麼咱們也能夠用with
關鍵字。
with lock: num = num + n num = num - n print num
死鎖的發生每每是兩個線程各自佔用了對方所須要用到的資源而都在等待對方釋放資源而形成的。
碰見死鎖後,程序則會一直暫停在那裏。直到系統將它們關閉。
說到Python的多線程編程,就會繞不過GIL。那麼GIL又是什麼鬼呢?
GIL聽說是Python中hardest的問題,想要完全瞭解GIL,必需要對操做系統設計、多線程編程、C語言、解釋器設計和CPython解釋器的實現有着很是完全的理解。
據廖雪峯中的教程中描述:
Python中的線程雖然是真正的線程,可是解釋器執行代碼的時候,會有一個GIL鎖(Global Interpreter Lock). 任何Python線程執行前,必須先得到GIL鎖。而後,每執行100條字節碼,解釋器就會自動釋放GIL鎖,讓別的線程有機會執行。這個GIL全局鎖實際上把全部線程的執行代碼都給上了鎖。所以,多線程在Python中只能交替進行,即便100個線程跑在100核CPU上,也只能用到1個核心。
GIL是Python解釋器設計的歷史遺留問題,一般咱們用的解釋器是官方實現完全CPython。
更多關於GIL設計的歷史淵源,能夠閱讀:
那麼是否是Python就是不能利用多核處理器任務了呢?咱們以前學到過多進程編程,每個進程都有一個獨立的GIL鎖,各進程互不影響。