python--threading多線程總結

threading用於提供線程相關的操做,線程是應用程序中工做的最小單元。python當前版本的多線程庫沒有實現優先級、線程組,線程也不能被中止、暫停、恢復、中斷。html

threading模塊提供的類:  
  Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。
python

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

threading 模塊提供的常量:安全

  threading.TIMEOUT_MAX 設置threading全局超時時間。多線程

 

Thread類


 

Thread是線程類,有兩種使用方法,直接傳入要運行的方法或從Thread繼承並覆蓋run():app

# coding:utf-8
import threading import time #方法一:將要執行的方法做爲參數傳給Thread的構造方法
def action(arg): time.sleep(1) print 'the arg is:%s\r' %arg for i in xrange(4): t =threading.Thread(target=action,args=(i,)) t.start() print 'main thread end!'

#方法二:從Thread繼承,並重寫run()
class MyThread(threading.Thread): def __init__(self,arg): super(MyThread, self).__init__()#注意:必定要顯式的調用父類的初始化函數。
        self.arg=arg def run(self):#定義每一個線程要運行的函數
        time.sleep(1) print 'the arg is:%s\r' % self.arg for i in xrange(4): t =MyThread(i) t.start() print 'main thread end!'
建立線程的兩種方法

 

構造方法: 
Thread(group=None, target=None, name=None, args=(), kwargs={}) 
ide

  group: 線程組,目前尚未實現,庫引用中提示必須是None; 
  target: 要執行的方法; 
  name: 線程名; 
  args/kwargs: 要傳入方法的參數。函數

實例方法: 
  isAlive(): 返回線程是否在運行。正在運行指啓動後、終止前。 

  get/setName(name): 獲取/設置線程名。 ui

  start():  線程準備就緒,等待CPU調度
  is/setDaemon(bool): 獲取/設置是後臺線程(默認前臺線程(False))。(在start以前設置)spa

    若是是後臺線程,主線程執行過程當中,後臺線程也在進行,主線程執行完畢後,後臺線程不論成功與否,主線程和後臺線程均中止
         若是是前臺線程,主線程執行過程當中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,程序中止
  start(): 啓動線程。 
  join([timeout]): 阻塞當前上下文環境的線程,直到調用此方法的線程終止或到達指定的timeout(可選參數)。

 

使用例子一(未設置setDeamon): 

 

# coding:utf-8
import threading import time def action(arg): time.sleep(1) print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName() print 'the arg is:%s\r' %arg time.sleep(1) for i in xrange(4): t =threading.Thread(target=action,args=(i,)) t.start() print 'main_thread end!'
setDeamon=Flase

 

main_thread end! sub thread start!the thread name is:Thread-2 the arg is:1 the arg is:0 sub thread start!the thread name is:Thread-4 the arg is:2 the arg is:3 Process finished with exit code 0 能夠看出,建立的4個「前臺」線程,主線程執行過程當中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,程序中止
運行結果

驗證了serDeamon(False)(默認)前臺線程,主線程執行過程當中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,主線程中止。

 

使用例子二(setDeamon=True)

# coding:utf-8
import threading import time def action(arg): time.sleep(1) print  'sub thread start!the thread name is:%s\r' % threading.currentThread().getName() print 'the arg is:%s\r' %arg time.sleep(1) for i in xrange(4): t =threading.Thread(target=action,args=(i,)) t.setDaemon(True)#設置線程爲後臺線程
 t.start() print 'main_thread end!'
setDeamon(True)
main_thread end!

Process finished with exit code 0

能夠看出,主線程執行完畢後,後臺線程不論是成功與否,主線程均中止
運行結果

驗證了serDeamon(True)後臺線程,主線程執行過程當中,後臺線程也在進行,主線程執行完畢後,後臺線程不論成功與否,主線程均中止。

 

使用例子三(設置join)

#coding:utf-8
import threading import time def action(arg): time.sleep(1) print  'sub thread start!the thread name is:%s ' % threading.currentThread().getName() print 'the arg is:%s ' %arg time.sleep(1) thread_list = []    #線程存放列表
for i in xrange(4): t =threading.Thread(target=action,args=(i,)) t.setDaemon(True) thread_list.append(t) for t in thread_list: t.start() for t in thread_list: t.join()
join用法
sub thread start!the thread name is:Thread-2 the arg is:1 sub thread start!the thread name is:Thread-3 the arg is:2 sub thread start!the thread name is:Thread-1 the arg is:0 sub thread start!the thread name is:Thread-4 the arg is:3 main_thread end! Process finished with exit code 0 設置join以後,主線程等待子線程所有執行完成後或者子線程超時後,主線程才結束
運行結果

驗證了 join()阻塞當前上下文環境的線程,直到調用此方法的線程終止或到達指定的timeout,即便設置了setDeamon(True)主線程依然要等待子線程結束。

使用例子四(join不穩當的用法,使多線程編程順序執行)

#coding:utf-8
import threading import time def action(arg): time.sleep(1) print  'sub thread start!the thread name is:%s ' % threading.currentThread().getName() print 'the arg is:%s ' %arg time.sleep(1) for i in xrange(4): t =threading.Thread(target=action,args=(i,)) t.setDaemon(True) t.start() t.join() print 'main_thread end!'
join不穩當用法
sub thread start!the thread name is:Thread-1 the arg is:0 sub thread start!the thread name is:Thread-2 the arg is:1 sub thread start!the thread name is:Thread-3 the arg is:2 sub thread start!the thread name is:Thread-4 the arg is:3 main_thread end! Process finished with exit code 0 能夠看出此時,程序只能順序執行,每一個線程都被上一個線程的join阻塞,使得「多線程」失去了多線程意義。
運行結果

 

 

Lock、Rlock類


 

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

Lock(指令鎖)是可用的最低級的同步指令。Lock處於鎖定狀態時,不被特定的線程擁有。Lock包含兩種狀態——鎖定和非鎖定,以及兩個基本的方法。

能夠認爲Lock有一個鎖定池,當線程請求鎖定時,將線程至於池中,直到得到鎖定後出池。池中的線程處於狀態圖中的同步阻塞狀態。

RLock(可重入鎖)是一個能夠被同一個線程請求屢次的同步指令。RLock使用了「擁有的線程」和「遞歸等級」的概念,處於鎖定狀態時,RLock被某個線程擁有。擁有RLock的線程能夠再次調用acquire(),釋放鎖時須要調用release()相同次數。

能夠認爲RLock包含一個鎖定池和一個初始值爲0的計數器,每次成功調用 acquire()/release(),計數器將+1/-1,爲0時鎖處於未鎖定狀態。

簡言之:Lock屬於全局,Rlock屬於線程。

構造方法: 
Lock(),Rlock(),推薦使用Rlock()

實例方法: 
  acquire([timeout]): 嘗試得到鎖定。使線程進入同步阻塞狀態。 

  release(): 釋放鎖。使用前線程必須已得到鎖定,不然將拋出異常。

例子一(未使用鎖):

#coding:utf-8
import threading import time gl_num = 0 def show(arg): global gl_num time.sleep(1) gl_num +=1
    print gl_num for i in range(10): t = threading.Thread(target=show, args=(i,)) t.start() print 'main thread stop'
未使用鎖
main thread stop 12

 3
4
568
 9

910 Process finished with exit code 0 屢次運行可能產生混亂。這種場景就是適合使用鎖的場景。
運行結果

 

例子二(使用鎖):

# coding:utf-8

import threading import time gl_num = 0 lock = threading.RLock() # 調用acquire([timeout])時,線程將一直阻塞, # 直到得到鎖定或者直到timeout秒後(timeout參數可選)。 # 返回是否得到鎖。
def Func(): lock.acquire() global gl_num gl_num += 1 time.sleep(1) print gl_num lock.release() for i in range(10): t = threading.Thread(target=Func) t.start()
使用Lock
1
2
3
4
5
6
7
8
9
10 Process finished with exit code 0 能夠看出,全局變量在在每次被調用時都要得到鎖,才能操做,所以保證了共享數據的安全性
運行結果

 

Lock對比Rlock

#coding:utf-8

import threading
lock = threading.Lock() #Lock對象
lock.acquire()
lock.acquire()  #產生了死鎖。
lock.release()
lock.release()
print lock.acquire()


import threading
rLock = threading.RLock()  #RLock對象
rLock.acquire()
rLock.acquire() #在同一線程內,程序不會堵塞。
rLock.release()
rLock.release()

 

Condition類


 

  Condition(條件變量)一般與一個鎖關聯。須要在多個Contidion中共享一個鎖時,能夠傳遞一個Lock/RLock實例給構造方法,不然它將本身生成一個RLock實例。

  能夠認爲,除了Lock帶有的鎖定池外,Condition還包含一個等待池,池中的線程處於等待阻塞狀態,直到另外一個線程調用notify()/notifyAll()通知;獲得通知後線程進入鎖定池等待鎖定。

構造方法: 
Condition([lock/rlock])

實例方法: 
  acquire([timeout])/release(): 調用關聯的鎖的相應方法。 

  wait([timeout]): 調用這個方法將使線程進入Condition的等待池等待通知,並釋放鎖。使用前線程必須已得到鎖定,不然將拋出異常。 
  notify(): 調用這個方法將從等待池挑選一個線程並通知,收到通知的線程將自動調用acquire()嘗試得到鎖定(進入鎖定池);其餘線程仍然在等待池中。調用這個方法不會釋放鎖定。使用前線程必須已得到鎖定,不然將拋出異常。 
  notifyAll(): 調用這個方法將通知等待池中全部的線程,這些線程都將進入鎖定池嘗試得到鎖定。調用這個方法不會釋放鎖定。使用前線程必須已得到鎖定,不然將拋出異常。

 

例子一:生產者消費者模型

# encoding: UTF-8
import threading import time # 商品
product = None # 條件變量
con = threading.Condition() # 生產者方法
def produce(): global product if con.acquire(): while True: if product is None: print 'produce...' product = 'anything'

                # 通知消費者,商品已經生產
 con.notify() # 等待通知
 con.wait() time.sleep(2) # 消費者方法
def consume(): global product if con.acquire(): while True: if product is not None: print 'consume...' product = None # 通知生產者,商品已經沒了
 con.notify() # 等待通知
 con.wait() time.sleep(2) t1 = threading.Thread(target=produce) t2 = threading.Thread(target=consume) t2.start() t1.start()
生產者消費者模型
produce... consume... produce... consume... produce... consume... produce... consume... produce... consume... Process finished with exit code -1 程序不斷循環運行下去。重複生產消費過程。
運行結果

例子二:生產者消費者模型

import threading import time condition = threading.Condition() products = 0 class Producer(threading.Thread): def run(self): global products while True: if condition.acquire(): if products < 10: products += 1; print "Producer(%s):deliver one, now products:%s" %(self.name, products) condition.notify()#不釋放鎖定,所以須要下面一句
 condition.release() else: print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products) condition.wait();#自動釋放鎖定
                time.sleep(2) class Consumer(threading.Thread): def run(self): global products while True: if condition.acquire(): if products > 1: products -= 1
                    print "Consumer(%s):consume one, now products:%s" %(self.name, products) condition.notify() condition.release() else: print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products) condition.wait(); time.sleep(2) if __name__ == "__main__": for p in range(0, 2): p = Producer() p.start() for c in range(0, 3): c = Consumer() c.start()
生產者消費者模型

例子三:

import threading alist = None condition = threading.Condition() def doSet(): if condition.acquire(): while alist is None: condition.wait() for i in range(len(alist))[::-1]: alist[i] = 1 condition.release() def doPrint(): if condition.acquire(): while alist is None: condition.wait() for i in alist: print i, print condition.release() def doCreate(): global alist if condition.acquire(): if alist is None: alist = [0 for i in range(10)] condition.notifyAll() condition.release() tset = threading.Thread(target=doSet,name='tset') tprint = threading.Thread(target=doPrint,name='tprint') tcreate = threading.Thread(target=doCreate,name='tcreate') tset.start() tprint.start() tcreate.start()
生產者消費者模型

 

Event類


 

  Event(事件)是最簡單的線程通訊機制之一:一個線程通知事件,其餘線程等待事件。Event內置了一個初始爲False的標誌,當調用set()時設爲True,調用clear()時重置爲 False。wait()將阻塞線程至等待阻塞狀態。

  Event其實就是一個簡化版的 Condition。Event沒有鎖,沒法使線程進入同步阻塞狀態。

構造方法: 
Event()

實例方法: 
  isSet(): 當內置標誌爲True時返回True。 

  set(): 將標誌設爲True,並通知全部處於等待阻塞狀態的線程恢復運行狀態。 
  clear(): 將標誌設爲False。 
  wait([timeout]): 若是標誌爲True將當即返回,不然阻塞線程至等待阻塞狀態,等待其餘線程調用set()。

 

例子一

# encoding: UTF-8
import threading import time event = threading.Event() def func(): # 等待事件,進入等待阻塞狀態
    print '%s wait for event...' % threading.currentThread().getName() event.wait() # 收到事件後進入運行狀態
    print '%s recv event.' % threading.currentThread().getName() t1 = threading.Thread(target=func) t2 = threading.Thread(target=func) t1.start() t2.start() time.sleep(2) # 發送事件通知
print 'MainThread set event.' event.set()
View Code

 

Thread-1 wait for event... Thread-2 wait for event... #2秒後。。。
MainThread set event. Thread-1 recv event. Thread-2 recv event. Process finished with exit code 0
View Code

 

timer類


 

  Timer(定時器)是Thread的派生類,用於在指定時間後調用一個方法。

構造方法: 
Timer(interval, function, args=[], kwargs={}) 

  interval: 指定的時間 
  function: 要執行的方法 
  args/kwargs: 方法的參數

實例方法: 
Timer從Thread派生,沒有增長實例方法。

例子一:

# encoding: UTF-8
import threading def func(): print 'hello timer!' timer = threading.Timer(5, func) timer.start()
View Code

線程延遲5秒後執行。

 

local類


 

 

  local是一個小寫字母開頭的類,用於管理 thread-local(線程局部的)數據。對於同一個local,線程沒法訪問其餘線程設置的屬性;線程設置的屬性不會被其餘線程設置的同名屬性替換。

  能夠把local當作是一個「線程-屬性字典」的字典,local封裝了從自身使用線程做爲 key檢索對應的屬性字典、再使用屬性名做爲key檢索屬性值的細節。

# encoding: UTF-8
import threading local = threading.local() local.tname = 'main'
 
def func(): local.tname = 'notmain'
    print local.tname t1 = threading.Thread(target=func) t1.start() t1.join() print local.tname
View Code
notmain
main
運行結果

 

參考文章連接:

  http://www.cnblogs.com/huxi/archive/2010/06/26/1765808.html

  http://www.cnblogs.com/wupeiqi/articles/5040827.html

相關文章
相關標籤/搜索