Thread 是threading模塊中最重要的類之一,可使用它來建立線程。有兩種方式來建立線程:一種是經過繼承Thread類,重寫它的run方法;另外一種是建立一個threading.Thread對象,在它的初始化函數(__init__)中將可調用對象做爲參數傳入。下面分別舉例說明。先來看看經過繼承threading.Thread類來建立線程的例子:html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#coding=gbk
import threading, time, random
count = 0
class Counter(threading.Thread):
def __init__(self, lock, threadName):
'''@summary: 初始化對象。
@param lock: 瑣對象。
@param threadName: 線程名稱。
'''
super(Counter, self).__init__(name = threadName) #注意:必定要顯式的調用父類的初始
化函數。
self.lock = lock
def run(self):
'''@summary: 重寫父類run方法,在線程啓動後執行該方法內的代碼。
'''
global count
self.lock.acquire()
for i in xrange(10000):
count = count + 1
self.lock.release()
lock = threading.Lock()
for i in range(5):
Counter(lock, "thread-" + str(i)).start()
time.sleep(2) #確保線程都執行完畢
print count
|
在代碼中,咱們建立了一個Counter類,它繼承了threading.Thread。初始化函數接收兩個參數,一個是瑣對象,另外一個是線程的名稱。在Counter中,重寫了從父類繼承的run方法,run方法將一個全局變量逐一的增長10000。在接下來的代碼中,建立了五個Counter對象,分別調用其start方法。最後打印結果。這裏要說明一下run方法 和start方法: 它們都是從Thread繼承而來的,run()方法將在線程開啓後執行,能夠把相關的邏輯寫到run方法中(一般把run方法稱爲活動[Activity]。);start()方法用於啓動線程。python
再看看另一種建立線程的方法:git
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import threading, time, random
count = 0
lock = threading.Lock()
def doAdd():
'''@summary: 將全局變量count 逐一的增長10000。
'''
global count, lock
lock.acquire()
for i in xrange(10000):
count = count + 1
lock.release()
for i in range(5):
threading.Thread(target = doAdd, args = (), name = 'thread-' + str(i)).start()
time.sleep(2) #確保線程都執行完畢
print count
|
在這段代碼中,咱們定義了方法doAdd,它將全局變量count 逐一的增長10000。而後建立了5個Thread對象,把函數對象doAdd 做爲參數傳給它的初始化函數,再調用Thread對象的start方法,線程啓動後將執行doAdd函數。這裏有必要介紹一下threading.Thread類的初始化函數原型:github
def __init__(self, group=None, target=None, name=None, args=(), kwargs={})dom
Thread類還定義瞭如下經常使用方法與屬性:ide
用於獲取和設置線程的名稱。函數
獲取線程的標識符。線程標識符是一個非零整數,只有在調用了start()方法以後該屬性纔有效,不然它只返回None。ui
判斷線程是不是激活的(alive)。從調用start()方法啓動線程,到run()方法執行完畢或遇到未處理異常而中斷 這段時間內,線程是激活的。spa
調用Thread.join將會使主調線程堵塞,直到被調用線程運行結束或超時。參數timeout是一個數值類型,表示超時時間,若是未提供該參數,那麼主調線程將一直堵塞到被調線程結束。下面舉個例子說明join()的使用:線程
1
2
3
4
5
6
7
8
9
10
11
|
import threading, time
def doWaiting():
print 'start waiting:', time.strftime('%H:%M:%S')
time.sleep(3)
print 'stop waiting', time.strftime('%H:%M:%S')
thread1 = threading.Thread(target = doWaiting)
thread1.start()
time.sleep(1) #確保線程thread1已經啓動
print 'start join'
thread1.join() #將一直堵塞,直到thread1運行結束。
print 'end join'
|
在threading模塊中,定義兩種類型的瑣:threading.Lock和threading.RLock。它們之間有一點細微的區別,經過比較下面兩段代碼來講明:
1
2
3
4
5
6
|
import threading
lock = threading.Lock() #Lock對象
lock.acquire()
lock.acquire() #產生了死瑣。
lock.release()
lock.release()
|
1
2
3
4
5
6
|
import threading
rLock = threading.RLock() #RLock對象
rLock.acquire()
rLock.acquire() #在同一線程內,程序不會堵塞。
rLock.release()
rLock.release()
|
這兩種瑣的主要區別是:RLock容許在同一線程中被屢次acquire。而Lock卻不容許這種狀況。注意:若是使用RLock,那麼acquire和release必須成對出現,即調用了n次acquire,必須調用n次的release才能真正釋放所佔用的瑣。
能夠把Condiftion理解爲一把高級的瑣,它提供了比Lock, RLock更高級的功能,容許咱們可以控制複雜的線程同步問題。threadiong.Condition在內部維護一個瑣對象(默認是RLock),能夠在建立Condigtion對象的時候把瑣對象做爲參數傳入。Condition也提供了acquire, release方法,其含義與瑣的acquire, release方法一致,其實它只是簡單的調用內部瑣對象的對應的方法而已。Condition還提供了以下方法(特別要注意:這些方法只有在佔用瑣(acquire)以後才能調用,不然將會報RuntimeError異常。):
wait方法釋放內部所佔用的瑣,同時線程被掛起,直至接收到通知被喚醒或超時(若是提供了timeout參數的話)。當線程被喚醒並從新佔有瑣的時候,程序纔會繼續執行下去。
喚醒一個掛起的線程(若是存在掛起的線程)。注意:notify()方法不會釋放所佔用的瑣。
喚醒全部掛起的線程(若是存在掛起的線程)。注意:這些方法不會釋放所佔用的瑣。
如今寫個捉迷藏的遊戲來具體介紹threading.Condition的基本使用。假設這個遊戲由兩我的來玩,一個藏(Hider),一個找(Seeker)。遊戲的規則以下:1. 遊戲開始以後,Seeker先把本身眼睛蒙上,蒙上眼睛後,就通知Hider;2. Hider接收通知後開始找地方將本身藏起來,藏好以後,再通知Seeker能夠找了; 3. Seeker接收到通知以後,就開始找Hider。Hider和Seeker都是獨立的個體,在程序中用兩個獨立的線程來表示,在遊戲過程當中,二者之間的行爲有必定的時序關係,咱們經過Condition來控制這種時序關係。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#---- Condition
#---- 捉迷藏的遊戲
import threading, time
class Hider(threading.Thread):
def __init__(self, cond, name):
super(Hider, self).__init__()
self.cond = cond
self.name = name
def run(self):
time.sleep(1) #確保先運行Seeker中的方法
self.cond.acquire() #b
print self.name + ': 我已經把眼睛蒙上了'
self.cond.notify()
self.cond.wait() #c
#f
print self.name + ': 我找到你了 ~_~'
self.cond.notify()
self.cond.release()
#g
print self.name + ': 我贏了' #h
class Seeker(threading.Thread):
def __init__(self, cond, name):
super(Seeker, self).__init__()
self.cond = cond
self.name = name
def run(self):
self.cond.acquire()
self.cond.wait() #a #釋放對瑣的佔用,同時線程掛起在這裏,直到被notify並從新佔
有瑣。
#d
print self.name + ': 我已經藏好了,你快來找我吧'
self.cond.notify()
self.cond.wait() #e
#h
self.cond.release()
print self.name + ': 被你找到了,哎~~~'
cond = threading.Condition()
seeker = Seeker(cond, 'seeker')
hider = Hider(cond, 'hider')
seeker.start()
hider.start()
|
Event實現與Condition相似的功能,不過比Condition簡單一點。它經過維護內部的標識符來實現線程間的同步問題。(threading.Event和.NET中的System.Threading.ManualResetEvent類實現一樣的功能。)
堵塞線程,直到Event對象內部標識位被設爲True或超時(若是提供了參數timeout)。
將標識位設爲Ture
將標識伴設爲False。
判斷標識位是否爲Ture。
下面使用Event來實現捉迷藏的遊戲(可能用Event來實現不是很形象)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#---- Event
#---- 捉迷藏的遊戲
import threading, time
class Hider(threading.Thread):
def __init__(self, cond, name):
super(Hider, self).__init__()
self.cond = cond
self.name = name
def run(self):
time.sleep(1) #確保先運行Seeker中的方法
print self.name + ': 我已經把眼睛蒙上了'
self.cond.set()
time.sleep(1)
self.cond.wait()
print self.name + ': 我找到你了 ~_~'
self.cond.set()
print self.name + ': 我贏了'
class Seeker(threading.Thread):
def __init__(self, cond, name):
super(Seeker, self).__init__()
self.cond = cond
self.name = name
def run(self):
self.cond.wait()
print self.name + ': 我已經藏好了,你快來找我吧'
self.cond.set()
time.sleep(1)
self.cond.wait()
print self.name + ': 被你找到了,哎~~~'
cond = threading.Event()
seeker = Seeker(cond, 'seeker')
hider = Hider(cond, 'hider')
seeker.start()
hider.start()
|
threading.Timer是threading.Thread的子類,能夠在指定時間間隔後執行某個操做。下面是Python手冊上提供的一個例子:
1
2
3
4
|
def hello():
print "hello, world"
t = Timer(3, hello)
t.start() # 3秒鐘以後執行hello函數。
|
threading模塊中還有一些經常使用的方法沒有介紹:
獲取當前活動的(alive)線程的個數。
獲取當前的線程對象(Thread object)。
獲取當前全部活動線程的列表。
設置一個跟蹤函數,用於在run()執行以前被調用。
設置一個跟蹤函數,用於在run()執行完畢以後調用。
threading模塊的內容不少,一篇文章很難寫全,更多關於threading模塊的信息,請查詢Python手冊 threading模塊。