關於python執行緒模組threading的學習總結:threading.Thread物件的join方法
如果想了解什麼是執行緒,推薦看一看這篇文章,真的是生動形象:趣文:我是一個執行緒
1.子執行緒不使用join方法
join方法主要是會阻塞主執行緒,在子執行緒結束執行前,主執行緒會被阻塞等待。這裡用一個例子來說明:
# encoding=utf8 import threading import time def now(): return '%.3f' % time.time() def test(n): print 'start %s at: %s' % (n, now()) time.sleep(n) print 'end %s at: %s' % (n, now()) def main(): print 'start main at: %s' % now() threadpool = [] for i in xrange(1, 4): th = threading.Thread(target=test, args=(i,)) threadpool.append(th) for th in threadpool: th.start() # for th in threadpool: # th.join() print 'main end at: %s' % now() if __name__ == '__main__': main()
在上面的例子中,每個子執行緒都會執行test方法,為了方便看結果,使每個子執行緒的sleep時間不同。
當前只是呼叫了每個子執行緒的start方法,並沒有呼叫join方法,此時執行結果:
start main at: 1521721709.912
start 1 at: 1521721709.913
start 2 at: 1521721709.913
start 3 at: 1521721709.913
main end at: 1521721709.913
end 1 at: 1521721710.913
end 2 at: 1521721711.913
end 3 at: 1521721712.913
通過結果可以看出,主執行緒完成第一次列印後(start main at: 1521721709.912),其他子執行緒同時開始,但是主執行緒並沒有等待子執行緒結束才結束,主執行緒繼續執行第二次列印(main end at: 1521721709.913),接著其他子執行緒因為各自sleep的時間不同而相繼結束。
2.子執行緒使用join方法
下面再看一下使用join方法後的結果(將上面註釋掉的部分取消):
start main at: 1521722097.382
start 1 at: 1521722097.382
start 2 at: 1521722097.382
start 3 at: 1521722097.382
end 1 at: 1521722098.382
end 2 at: 1521722099.382
end 3 at: 1521722100.383
main end at: 1521722100.383
不難看出,主執行緒阻塞等待子執行緒完成後,自己才結束執行。
3.join方法的timeout引數
然後可以給在join函式傳一個timeout引數的,看看它的作用是什麼,這裡修改了一下程式碼:
# encoding=utf8
import threading
import time
def now():
return '%.3f' % time.time()
def test(n):
while 1:
print str(n) * 6
time.sleep(5)
def main():
print 'start main at: %s' % now()
threadpool = []
for i in xrange(1, 3):
th = threading.Thread(target=test, args=(i, ))
threadpool.append(th)
for th in threadpool:
th.start()
for th in threadpool:
th.join(5)
print 'main end at: %s' % now()
if __name__ == '__main__':
main()
這裡設定每個執行緒的timeout都是5,執行部分結果如下:
start main at: 1521723210.825
111111
222222
222222
111111
main end at: 1521723220.825
111111
222222
111111
222222
......
因為每個子執行緒執行的是一個while迴圈,實際上是會一直執行下去的(兩個子執行緒一直列印111111,222222),如果不給join方法設定timeout,那麼主執行緒會一直等下去,永遠不會執行最後的“print 'main end at: %s' % now()”語句,但是上面的程式碼設定了timeout為5秒,通過執行結果可以看出,主執行緒一共等待了10秒後結束了自己的執行。所以可以知道,join方法的timeout引數表示了主執行緒被每個子執行緒阻塞等待的時間。
4.說說setDaemon
使用join方法是為了讓主執行緒等待子線結束後再做其他事情,setDaemon方法正好相反,它是為了保證主執行緒結束的時候,整個程序就結束,不會等待所有子執行緒執行完才結束。修改一下上面的程式碼:
# encoding=utf8
import threading
import time
def now():
return '%.3f' % time.time()
def test(n):
time.sleep(n)
print '%s has ran' % (str(n) * 6)
def main():
print 'start main at: %s' % now()
threadpool = []
for i in xrange(2):
th = threading.Thread(target=test, args=(i, ))
threadpool.append(th)
for th in threadpool:
th.setDaemon(True)
th.start()
print 'main end at: %s' % now()
if __name__ == '__main__':
main()
以下是執行結果:
start main at: 1521726104.773
000000 has ran
main end at: 1521726104.773
通過結果可以看出,雖然建立了兩個子執行緒,第一個子執行緒的sleep時間為0,所以可以和主執行緒同時執行,但是第二個子執行緒本身會先sleep1秒,這時候主執行緒已經執行完,整個程式退出,並沒有接著執行第二個子執行緒。
需要注意的是,setDaemon方法要在呼叫start方法前設定。