以前提了Python多線程的一點使用,今天介紹更好的threading模塊,它提供了Thread類和一些比較好用的同步機制。多線程
先介紹Thread類app
threading模塊中的Thread類有不少thread模塊裏沒有的方法,通常使用時能夠選擇幾種方法裏的一種:函數
能夠看看它有哪些方法oop
函數 | 描述 |
start() | 開始線程的執行 |
run()spa |
定義線程的功能的函數(通常會被子類重寫) |
join(timeout=None) | 程序掛起,知道線程結束,若是給了timeout,最多阻塞timeout秒 |
getName()線程 |
返回線程的名字 |
setName(name) | 設置線程的名字 |
isAlive() | 布爾標誌,表示這個線程是否還在運行中 |
isDaemon() | 返回線程的daemon標誌 |
setDaemon(daemonic) | 把線程的daemon標誌設置成daemonic |
用threading模塊重寫咱們上次的例子:code
import threading from time import sleep, ctime loops = [4, 2] def loop(nloop, nsec): print 'start loop%s at: %s\n' % (nloop, ctime()), sleep(nsec) print 'loop%s done at: %s\n' % (nloop, ctime()), def main(): print 'starting at: %s\n' % ctime(), 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: %s\n' %ctime(), if __name__ == '__main__': main()
結果也是以下顯示:對象
>>> starting at: Sun Jan 03 11:37:43 2016 start loop0 at: Sun Jan 03 11:37:43 2016 start loop1 at: Sun Jan 03 11:37:43 2016 loop1 done at: Sun Jan 03 11:37:45 2016 loop0 done at: Sun Jan 03 11:37:47 2016 all DONE at: Sun Jan 03 11:37:47 2016
比起昨天的鎖,這裏只須要簡單地對每一個線程使用join()函數就能夠了。blog
join()看上去會比一個等待鎖釋放的無限循環清楚一些。它另外一個很重要的方面是能夠徹底不用調用,一旦線程啓動後就會一直執行,知道線程的函數結束退出位置。get
上面使用的是一種傳遞函數給Thread模塊,也能夠在建立線程的時候,傳一個可調用的類的實例來供線程啓動的時候執行,這是一種更面爲對象的方法。
代碼以下:
import threading from time import sleep, ctime loops = [4, 2] class ThreadFunc(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) def loop(nloop, nsec): print 'start loop %s at: %s\n' %(nloop, ctime()), sleep(nsec) print 'loop %s done at: %s\n' %(nloop, ctime()), def main(): print 'starting at:', ctime() threads = [] nloops = range(len(loops)) for i in nloops: t = threading.Thread( target = ThreadFunc(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()
結果和上面是同樣的,這裏就不貼了。
能夠看到咱們怎家了一個ThreadFunc類和建立Thread對象時實例化一個可調用類ThreadFunc的類對象。
建立線程時,Thread對象會調用咱們的ThreadFunc對象,會用到一個特殊函數__call__(),因爲咱們已經有了要用的參數,因此再也不傳到Thread()構造器中。
最後一種方法是從Thread類中派生一個子類,而後創造這個子類的實例。
import threading from time import sleep, ctime loops = [2, 4] 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): apply(self.func, self.args) def loop(nloop, nsec): print 'start loop%s at: %s' %(nloop, ctime()) sleep(nsec) print 'loop%s done at:%s' %(nloop, ctime()) def main(): print 'starting at:%s' % ctime() 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: %s' % ctime() if __name__ == '__main__': main()