如果想了解什麼是線程,推薦看一看這篇文章,真的是生動形象:趣文:我是一個線程
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方法前設置。