1.python中多線程編程
進程是由若干線程組成的,一個進程至少有一個線程。由於線程是作業系統直接支援的執行單元,因此,進階語言通常都內建多線程的支援,Python也不例外,並且,Python的線程是真正的Posix Thread,而不是類比出來的線程。
Python的標準庫提供了兩個模組:_thread和threading,thread是低級模組,threading是進階模組,對thread進行了封裝。絕大多數情況下,我們只需要使用threading這個進階模組。如下為使用threading模組來實現多線程編程的常式:
import time, threading# 新線程執行的代碼:def loop(): print('thread %s is running...' % threading.current_thread().name) n = 0 while n < 5: n = n + 1 print('thread %s >>> %s' % (threading.current_thread().name, n)) time.sleep(1) print('thread %s ended.' % threading.current_thread().name)print('thread %s is running...' % threading.current_thread().name)t = threading.Thread(target=loop, name='LoopThread')t.start()t.join()print('thread %s ended.' % threading.current_thread().name)運行結果如下:
thread MainThread is running...thread LoopThread is running...thread LoopThread >>> 1thread LoopThread >>> 2thread LoopThread >>> 3thread LoopThread >>> 4thread LoopThread >>> 5thread LoopThread ended.thread MainThread ended.
由於任何進程預設就會啟動一個線程,我們把該線程稱為主線程,主線程又可以啟動新的線程,Python的threading模組有個current_thread()函數,它永遠返回當前線程的執行個體。主線程執行個體的名字叫MainThread,子線程的名字在建立時指定,我們用LoopThread命名子線程。名字僅僅在列印時用來顯示,完全沒有其他意義,如果不起名字Python就自動給線程命名為Thread-1,Thread-2……
start函數是啟動線程,調用start方法後,線程將開始執行了。join是阻塞方法,它會阻塞調用join函數的線程,直到對應的線程執行完畢。
2.多線程中鎖的使用
多線程和多進程最大的不同在於,多進程中,同一個變數,各自有一份拷貝存在於每個進程中,互不影響,而多線程中,所有變數都由所有線程共用,所以,任何一個變數都可以被任何一個線程修改,因此,線程之間共用資料最大的危險在於多個線程同時改一個變數,把內容給改亂了。
import time, threading# 假定這是你的銀行存款:balance = 0lock = threading.Lock()def change_it(n): # 先存後取,結果應該為0: global balance balance = balance + n balance = balance - ndef run_thread(n): for i in range(100000): # 先要擷取鎖: lock.acquire() try: # 放心地改吧: change_it(n) finally: # 改完了一定要釋放鎖: lock.release()t1 = threading.Thread(target=run_thread, args=(5,))t2 = threading.Thread(target=run_thread, args=(8,))t1.start()t2.start()t1.join()t2.join()print(balance)
程式運行結果為0.
當多個線程同時執行lock.acquire()時,只有一個線程能成功地擷取鎖,然後繼續執行代碼,其他線程就繼續等待直到獲得鎖為止。獲得鎖的線程用完後一定要釋放鎖,否則那些苦苦等待鎖的線程將永遠等待下去,成為死線程。所以我們用try...finally來確保鎖一定會被釋放。
鎖的好處就是確保了某段關鍵代碼只能由一個線程從頭到尾完整地執行,壞處當然也很多,首先是阻止了多線程並發執行,包含鎖的某段代碼實際上只能以單線程模式執行,效率就大大地下降了。其次,由於可以存在多個鎖,不同的線程持有不同的鎖,並試圖擷取對方持有的鎖時,可能會造成死結,導致多個線程全部掛起,既不能執行,也無法結束,只能靠作業系統強制終止。
學習資料參考於:
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143192823818768cd506abbc94eb5916192364506fa5d000