1. 程式人生 > >關於python執行緒模組threading的學習總結:threading.Thread物件的join方法

關於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方法前設定。