python多執行緒程式設計(二)--threading模組
threading模組物件
物件 |
描述 |
Thread |
一個執行緒的執行物件 |
Lock |
鎖物件 |
RLock |
可重入鎖物件,使單執行緒可以再次獲得已經獲得了的鎖(遞迴鎖定) |
Condition |
條件變數,讓一個執行緒停下來,等待其它執行緒滿足了某個條件 |
Event |
事件物件,通用的條件變數 |
Semaphore |
訊號量 |
BoundedSemaphore |
與Semaphore類似,只是它不允許超過初始值 |
Timer |
與Thread相似,不過它要等待一段時間才開始執行 |
threading的Thread類是最主要的執行物件。
Thread
函式 |
描述 |
start() |
執行緒開始執行 |
run() |
執行緒功能函式 |
join(timeout=None) |
程式掛起,直到執行緒結束;如果給了timeout,則最多阻塞timeout秒 |
getName() |
返回執行緒名字 |
setName(name) |
設定執行緒名字 |
isAlive() |
這個執行緒是否還在執行 |
isDaemon() |
返回執行緒的daemon標誌 |
setDaemon(daemonic) |
設定執行緒的daemon屬性,一定要在呼叫start()函式前呼叫 |
使用Thread類,我們介紹三種方法來建立執行緒。
● 建立一個Thread的例項,傳給它一個函式
● 建立一個Thread的例項,傳給它一個可呼叫的類物件
● 從Thread派生出一個子類,建立一個這個子類的例項
下面看第一種,建立一個Thread的例項,傳給它一個函式
我們將初始化一個Thread物件,把函式(及其引數)傳進去。這種方式例項化一個Thread與呼叫thread.start_new_thread()之間的最大區別就是,新執行緒不會立即開始。當你建立執行緒物件又不想立即開始執行的時候,這是很有用的。
#coding: utf-8 import threading from time import sleep, ctime loops = [4,2] def loop(nloop, nsec): print 'loop', nloop, 'start at:', ctime() print 'loop %d 掛起%d秒' % (nloop, nsec) sleep(nsec) print 'loop', nloop, 'done at:', ctime() def main(): print 'main thread start!' threads = [] #執行緒列表 nloops = range(len(loops)) for i in nloops: t = threading.Thread(target=loop, args=(i, loops[i])) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() #等待執行緒結束 print 'all done at:', ctime() if __name__ == '__main__': main()
執行結果:
這種方式就省了管理一堆鎖的功夫了,只要對每個執行緒呼叫join()函式,就會等到執行緒結束。
另外,如果你的主執行緒除了等執行緒結束外,還有其它的事情要做(如處理或等待其它的客戶請求),那就不用呼叫join()。一旦執行緒啟動後,就會一直執行,直到執行緒的函式結束,退出為止。所以只有在你要等待執行緒結束的時候才要呼叫join()。
第二種方式,建立一個Thread的例項,傳給它一個可呼叫的類物件
這種方式就是在第一種方式的情況下,將函式封裝進類物件裡面,由類物件提供功能函式。在建立Thread物件時會例項化這個類物件。
#coding: utf-8
import threading
from time import sleep, ctime
loops = [4,2]
class Func(object):
def __init__(self, func, args, name=""):
self.name = name
self.func = func
self.args =args
def __call__(self):
self.res = self.func(*self.args) #如果python版本是1.6以下,就使用apply(self.func, self.args)
def loop(nloop, nsec):
print 'loop', nloop, 'start at:', ctime()
print 'loop %d 掛起%d秒' % (nloop, nsec)
sleep(nsec)
print 'loop', nloop, 'done at:', ctime()
def main():
print 'main thread start!'
threads = [] #執行緒列表
nloops = range(len(loops))
for i in nloops:
t = threading.Thread(target=Func(loop, (i, loops[i]), loop.__name__))
threads.append(t)
for i in nloops:
threads[i].start()
for i in nloops:
threads[i].join() #等待執行緒結束
print 'all done at:', ctime()
if __name__ == '__main__':
main()
建立新執行緒的時候,Thread物件會呼叫我們的Func物件,這時會用到一個特殊函式__call__()。這是python的一個特性,只要定義型別的時候,實現__call__函式,這個型別就成為可呼叫的。比如實現了__call__函式的Func物件例項instance,形如instance(arg1,arg2,...)實際上呼叫的就是instance.__call__(arg1,arg2,...)
第三種方式,從Thread派生出一個子類,建立這個子類的例項
#coding: utf-8
import threading
from time import sleep, ctime
loops = [4,2]
class MyThread(threading.Thread):
def __init__(self, func, args, name=""):
threading.Thread.__init__(self)
self.name = name
self.func = func
self.args =args
def run(self):
self.res = self.func(*self.args)
def loop(nloop, nsec):
print 'loop', nloop, 'start at:', ctime()
print 'loop %d 掛起%d秒' % (nloop, nsec)
sleep(nsec)
print 'loop', nloop, 'done at:', ctime()
def main():
print 'main thread start!'
threads = []
nloops = range(len(loops))
for i in nloops:
t = MyThread(loop, (i, loops[i]), loop.__name__)
threads.append(t)
for i in nloops:
threads[i].start()
for i in nloops:
threads[i].join()
print 'all done at:', ctime()
if __name__ == '__main__':
main()
這種方式使建立執行緒物件的程式碼更簡潔。