python之多線程

  • 2019 年 10 月 8 日
  • 筆記

本來呢應該先看多進程的,但是由於我的虛擬機之前刪除了linux,所以現在沒有這個系統,可能無法編譯一些多進程的程序,於是我就想着先看多線程了。


多線程:

我們的程序一般都是多任務的,如果你沒有好好的利用好,運行時就會出現卡頓,甚至程序奔潰,這是因為所以的任務都擠在同一個地方。

多任務可以由多進程完成,而多進程可以由多線程完成。由於線程是操作系統直接支持的執行單元,因此,高級語言都有內置線程,而且python下的線程是真正的posix Thread,而不是模擬的線程。

在python中的標準庫提供了兩個模塊,一個是_thread和threading;前者是低級模塊,後者是高級模塊,我們就用threading模塊就可以,它對_thread進行了封裝。

啟動一個線程就是把一個函數傳入並創建thread實例,比如我們有一個輸出函數

由於任何進程默認就會啟動一個線程,我們把該線程稱為主線程,主線程又可以啟動新的線程,Python的threading模塊有個current_thread()函數,它永遠返回當前線程的實例。主線程實例的名字叫MainThread,子線程的名字在創建時指定,上例中我們用shuchu命名子線程。名字僅僅在打印時用來顯示,完全沒有其他意義,如果不起名字Python就自動給線程命名為Thread-1,Thread-2……

lock

線程鎖,因為在線程中所以的變量都由所以線程共享,所以所以變量都可能被修改,這樣就很容易造成混亂,這時候就需要線程鎖來協助了

假如當多個線程同時執行lock.acquire()時,只有一個線程能成功地獲取鎖,然後繼續執行代碼,其他線程就要繼續等待直到獲得鎖為止。

例子:

num = 0  def shuchu(n):      global num      num = num+n      num = num-nlock = threading.Lock()  def run(n):  for i in range(100000):            lock.acquire()         # 獲取鎖:try:                  shuchu(n)     #修改數據   finally:            lock.release()   #釋放鎖:run()

獲得鎖的線程用完後一定要用lock.release來釋放鎖,否則那些苦苦等待鎖的線程將永遠等待下去,成為死線程。所以我們用try…finally來確保鎖一定會被釋放。

假如當多個線程同時執行lock.acquire()時,只有一個線程能成功地獲取鎖,然後繼續執行代碼,其他線程就要繼續等待直到獲得鎖為止。

獲得鎖的線程用完後一定要用lock.release來釋放鎖,否則那些苦苦等待鎖的線程將永遠等待下去,成為死線程。所以我們用try…finally來確保鎖一定會被釋放。

鎖的好處就是確保了某段關鍵代碼只能由一個線程從頭到尾完整地執行,壞處當然也很多,首先是阻止了多線程並發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率就大大地下降了。其次,由於可以存在多個鎖,不同的線程持有不同的鎖,並試圖獲取對方持有的鎖時,可能會造成死鎖,導致多個線程全部掛起,既不能執行,也無法結束,只能靠操作系統強制終止。

多線程編程,模型複雜,容易發生衝突,必須用鎖加以隔離,同時,又要小心死鎖的發生。

Python解釋器由於設計時有GIL全局鎖,導致了多線程無法利用多核