python——線程與多線程進階

  以前咱們已經學會如何在代碼塊中建立新的線程去執行咱們要同步執行的多個任務,可是線程的世界遠不止如此。接下來,咱們要介紹的是整個threading模塊。threading基於Java的線程模型設計。鎖(Lock)和條件變量(Condition)在Java中是對象的基本行爲(每個對象都自帶了鎖和條件變量),而在Python中則是獨立的對象,因此python的threading模塊中還提供了Lock,Rlock,Condition,Event等經常使用類,它們在python中是獨立於Tread模塊的,可是卻與線程緊密相關,不可分割。html

  須要注意的是:python的線程中沒有優先級、線程組,也不能被中止、暫停、恢復、中斷,線程只能隨着線程中的代碼執行完畢而被銷燬。查了n多資料以後終於接受了以上事實,我的以爲這是python的一個坑,致使了我在實現線程池的時候沒法中止已經注入了方法且執行超時的線程。python

threading模塊提供的類: 
  Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local.
多線程

threading 模塊提供的經常使用方法:
  threading.currentThread(): 返回當前的線程變量。
  threading.enumerate(): 返回一個包含正在運行的線程的list。正在運行指線程啓動後、結束前,不包括啓動前和終止後的線程。
  threading.activeCount(): 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。app

threading模塊經常使用類詳解ide

Thread類:咱們使用Thread類來建立新的線程學習

  • start            線程準備就緒,等待CPU調度
  • setName      爲線程設置名稱
  • getName      獲取線程名稱
  • setDaemon  設置爲後臺線程或前臺線程(默認)
                      若是是後臺線程,主線程執行過程當中,後臺線程也在進行,主線程執行完畢後,後臺線程不論成功與否,均中止
                      若是是前臺線程,主線程執行過程當中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,程序中止
  • join             逐個執行每一個線程,執行完畢後繼續往下執行,該方法是有高級用法的,代碼在下面
  • run             線程被cpu調度後執行Thread類對象的run方法
 1 import time
 2 import threading
 3 
 4 def printNum(a):
 5     print 'num:',a
 6     time.sleep(1)
 7 
 8 def ThreadTest(i):
 9     return threading.Thread(target=printNum, args=(999,))
10 
11 thread_arr = []
12 for i in range(10):
13     t = ThreadTest(i)
14     thread_arr.append(t)
15 
16 for t in thread_arr:
17     t.start()
18 
19 for t in thread_arr:
20     t.join()
21 
22 print 'finished'
join進階用法

Lock類和Rlock類:因爲線程之間隨機調度:某線程可能在執行n條後,CPU接着執行其餘線程。爲了多個線程同時操做一個內存中的資源時不產生混亂,咱們使用鎖ui

  • acquire   給線程上鎖 
  • release   給線程解鎖

    

  不管是lock仍是rlock,提供的方法都很是簡單,acquire和release。可是rlock和lock的區別是什麼呢?RLock容許在同一線程中被屢次acquire。而Lock卻不容許這種狀況。注意:若是使用RLock,那麼acquire和release必須成對出現,即調用了n次acquire,必須調用n次的release才能真正釋放所佔用的鎖。spa

 1 #!/usr/bin/env python
 2 #-*-coding:utf-8-*-
 3 __author__ = 'Eva_J'
 4 
 5 import threading   
 6 lock = threading.Lock() #Lock對象   
 7 lock.acquire()   
 8 lock.acquire()  #產生了死鎖。   
 9 lock.release()   
10 lock.release()   
11 
12 
13 import threading   
14 rLock = threading.RLock()  #RLock對象   
15 rLock.acquire()   
16 rLock.acquire() #在同一線程內,程序不會堵塞。   
17 rLock.release()   
18 rLock.release()   
lock vs rlock Code

Condition類:條件變量對象能讓一個線程停下來,等待其它線程知足了某個「條件」。如,狀態的改變或值的改變。線程

  • acquire   給線程上鎖 
  • wait           wait方法釋放當前線程佔用的鎖,同時掛起線程,直至被喚醒或超時(需timeout參數)。當線程被喚醒並從新佔有鎖的時候,程序纔會繼續執行下去。
  • notify     喚醒一個掛起的線程(若是存在掛起的線程)。注:notify()方法不會釋放所佔用的鎖。
  • notifyall  調用這個方法將通知等待池中全部線程,這些線程都將進入鎖定池嘗試得到鎖定。此方法不會釋放鎖定。使用前線程必須已得到鎖定,不然將拋出異常。

  比較經典的例子是下面這個生產者與消費者的例子,這個例子網上一搜處處都是,這裏簡單解釋一下這段代碼的意義,代碼中寫了兩個類,Consumer和Producer,分別繼承了Thread類,咱們分別初始化這兩個類得到了c和p對象,並啓動這兩個線程。則這兩個線程去執行run方法(這裏與Thread類內部的調度有關),定義了producer全局變量和condition對象爲全局變量,當producer不大於1時,消費者線程被condition對象阻塞,不能繼續消費(這裏是再也不遞減),當producer不小於10時,生產者線程被condition對象阻塞,再也不生產(這裏是再也不累加),代碼在下面,拿去執行,斷點一下就明白了。設計

 1 #!/usr/bin/env python
 2 #-*-coding:utf-8-*-
 3 __author__ = 'Eva_J'
 4 
 5 import threading
 6 import time
 7 
 8 condition = threading.Condition()
 9 products = 0
10 
11 class Producer(threading.Thread):
12     def __init__(self):
13         threading.Thread.__init__(self)
14 
15     def run(self):
16         global condition, products
17         while True:
18             if condition.acquire():
19                 if products < 10:
20                     products += 1;
21                     print "Producer(%s):deliver one, now products:%s" %(self.name, products)
22                     condition.notify()
23                 else:
24                     print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)
25                     condition.wait();
26                 condition.release()
27                 time.sleep(2)
28 
29 class Consumer(threading.Thread):
30     def __init__(self):
31         threading.Thread.__init__(self)
32 
33     def run(self):
34         global condition, products
35         while True:
36             if condition.acquire():
37                 if products > 1:
38                     products -= 1
39                     print "Consumer(%s):consume one, now products:%s" %(self.name, products)
40                     condition.notify()
41                 else:
42                     print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)
43                     condition.wait();
44                 condition.release()
45                 time.sleep(2)
46 
47 if __name__ == "__main__":
48     for p in range(0, 2):
49         p = Producer()
50         p.start()
51 
52     for c in range(0, 10):
53         c = Consumer()
54         c.start()
condition Code

Event類:通用的條件變量。多個線程能夠等待某個事件的發生,在事件發生後,全部的線程都會被激活。

 

  • event.wait(timeout)  當Flag爲‘False’時,線程將被阻塞
  • clear                    將「Flag」設置爲False
  • set                      將「Flag」設置爲True
  • is_set                         返回當前‘Flag’

   這是一個比較關鍵的類,我在寫線程池的時候看到python的threadpool模塊也用到了。它的意義在於能夠控制屬於同一個線程類的多個實例化對象,讓他們同時阻塞或者執行。配合隊列來實現一個線程池很是好用。在接下里的博客中咱們還要繼續介紹。先放一個小例子在這裏練練手,瞭解一下event的用法。

 1 #!/usr/bin/env python
 2 #-*-coding:utf-8-*-
 3 __author__ = 'Eva_J'
 4 
 5 import threading 
 6 import time 
 7   
 8 event = threading.Event() 
 9   
10 def func(): 
11     # 等待事件,進入等待阻塞狀態 
12     print '%s wait for event...' % threading.currentThread().getName() 
13     event.wait() 
14      
15     # 收到事件後進入運行狀態 
16     print '%s recv event.' % threading.currentThread().getName() 
17   
18 t1 = threading.Thread(target=func) 
19 t2 = threading.Thread(target=func) 
20 t1.start() 
21 t2.start() 
22   
23 time.sleep(2) 
24   
25 # 發送事件通知 
26 print 'MainThread set event.'
27 event.set() 
event Code

 

參考文獻:

  python多線程學習小結:http://www.myexception.cn/perl-python/1688021.html

  python線程指南:http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html

  threading.RLock和threading.Lock:http://blog.sina.com.cn/s/blog_5dd2af0901012rad.html

  python的進程、線程與協程:http://www.cnblogs.com/wupeiqi/articles/5040827.html

相關文章
相關標籤/搜索