Python多線程
Python中實現多線程有兩種方式,一種基于_thread模塊(在Python2.x版本中為thread模塊,沒有下劃線)的start_new_thread()函數,另一種基于threading模塊的Thread類。
其實Python的多線程編程不能真正利用多核的CPU,但是用開源模塊使你的計算壓力分布到多核CPU上.........
一.使用start_new_thread()實現線程,是比較底層的實現方式,所有線程共享他們global數據,為了達到同步,模塊也提供了簡單的鎖機制
| _thread.start_new_thread(function, args[, kwargs]) |
| 啟動一個新的進程,并返回其標識符. 線程執行的函數需要的參數由args(必須為一個元組)提供,亦可通過可選參數kwargs提供關鍵字參數組 成的字典。當函數返回時,啟動的線程也 停止退出。如果函數中存在未處理異常,會打印堆棧跟蹤后線程停止退出(其他線程繼續執行)。 |
其中線程標識符是一個非0整數,并沒有直接意思,可以當作從一個線程組成的特殊字典中索引本線程的一個key,也可用_thread.get_ident()得到,在線程退出后,標識符會被系統回收。在線程執行過程中可以調用_thread.exit()終止本線程的執行。
二.使用Thread類來實現多線程,這種方式是對_thread模塊(如果沒有_thread,則為dummy_threading)的高級封裝,在這種方式下我們需創建新類繼承threading.Thread,和java一樣重寫threading.Thread的run方法即可.啟動線程用線程的start方法,它會調用我們重寫的run方法.
Thread類還定義了以下常用方法與屬性:
| Thread.getName() /Thread.setName() |
| 老方式用于獲取和設置線程的名稱,官方建議用Thread.name替代 |
| Thread.ident |
| 獲取線程的標識符。只有在調用start()方法執行后才有效,否則返回None。 |
| Thread.is_alive() |
| 判斷線程是否是激活的。 |
| Thread.join([timeout]) |
| 調用Thread.join將會使主調線程堵塞,直到被調用線程運行結束或超時。參數timeout是一個數值類型,表示超時時間,如果未提供該參數,那么主調線程將一直堵塞到被調線程結束。 |
Python中的鎖
先用_thread模塊的Lock鎖來實現生產者消費者問題,Lock對象是Python提供的低級線程控制工具,使用起來非常簡單,只需下面3條語句即可:
| _thread.allocate_lock()返回一個新Lock對象,即為一個新鎖 |
| lock.acquire() 相當于P操作,得到一個鎖, |
| lock.release()相當于V操作,釋放一個鎖 |
代碼如下:
另一個較高級的鎖為RLock鎖,RLock對象內部維護著一個Lock對象,它是一種可重入的對象。對于Lock對象而言,如果一個線程連續兩次進行acquire操作,那么由于第一次acquire之后沒有release,第二次acquire將掛起線程。這會導致Lock對象永遠不會release,使得線程死鎖。RLock對象允許一個線程多次對其進行acquire操作,因為在其內部通過一個counter變量維護著線程acquire的次數。而且每一次的acquire操作必須有一個release操作與之對應,在所有的release操作完成之后,別的線程才能申請該RLock對象。
threading模塊對Lock也提供和封裝,提供了更高級的同步方式(可以理解為更高級的鎖),包括threading.Event和threading.Condition,其中threading.Event為提供了簡單的同步方式:一個進程標記event,其他進程等待,只需下面的幾個方法即可:
| Event.wait([timeout]) |
| 堵塞線程,直到Event對象內部標識位被設為True或超時(如果提供了參數timeout)。 |
| Event.set() |
| 將標識號設為Ture |
| Event.clear() |
| 設為標識符False |
threading.Condition 可以把Condiftion理解為一把高級的瑣,它提供了比Lock, RLock更高級的功能,允許我們能夠控制復雜的線程同步問題。threadiong.Condition在內部維護一個瑣對象(默認是RLock),可以在創建Condigtion對象的時候把瑣對象作為參數傳入。Condition也提供了acquire, release方法,其含義與瑣的acquire, release方法一致,其實它只是簡單的調用內部瑣對象的對應的方法而已。Condition還提供了如下方法(特別要注意:這些方法只有在占用瑣(acquire)之后才能調用,否則將會報RuntimeError異常。):
| Condition.wait([timeout]): |
| wait方法釋放內部所占用的瑣,同時線程被掛起,直至接收到通知被喚醒或超時(如果提供了timeout參數的話)。當線程被喚醒并重新占有瑣的時候,程序才會繼續執行下去。 |
| Condition.notify(): |
| 喚醒一個掛起的線程(如果存在掛起的線程)。注意:notify()方法不會釋放所占用的瑣。 |
| Condition.notify_all() |
| 喚醒所有掛起的線程(如果存在掛起的線程)。注意:這些方法不會釋放所占用的瑣。 |
新聞熱點
疑難解答