從網(wǎng)上找到了兩篇言簡意賅的文章
https://www.cnblogs.com/fnng/p/3670789.html
http://blog.csdn.net/zhangzheng0413/article/details/41728869/
稍微修改總結(jié)一下
首先得先明白多個子線程之間是如何同時運行的(python2)
第一種情況:
import threading
from time import ctime,sleep
def music(func):
for i in range(2):
print "I was listening to %s. %s" %(func,ctime())
sleep(1)
def move(func):
for i in range(2):
print "I was at the %s! %s" %(func,ctime())
sleep(5)
if __name__ == '__main__':
music(u'愛情買賣')
move(u'阿凡達')
print "all over %s" %ctime()
運行結(jié)果為下
>>>
I was listening to 愛情買賣. Thu Apr 17 11:48:59 2014
I was listening to 愛情買賣. Thu Apr 17 11:49:00 2014
I was at the 阿凡達! Thu Apr 17 11:49:01 2014
I was at the 阿凡達! Thu Apr 17 11:49:06 2014
all over Thu Apr 17 11:49:11 2014
這種情況比較簡單,我們還沒有啟動子線程,所以輸出語句通過time.sleep方法按順序執(zhí)行下來
第二種情況我們啟用多線程:
import threading
from time import ctime,sleep
def music(func):
for i in range(2):
print "I was listening to %s. %s" %(func,ctime())
sleep(1)
def move(func):
for i in range(2):
print "I was at the %s! %s" %(func,ctime())
sleep(5)
threads = []
t1 = threading.Thread(target=music,args=(u'愛情買賣',))
threads.append(t1)
t2 = threading.Thread(target=move,args=(u'阿凡達',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start()
print "all over %s" %ctime()
利用threading.Thread(target=xxxx)創(chuàng)建線程,這里我們創(chuàng)建了兩個線程,并將他們添加到threads這個list中,這種情況執(zhí)行的關(guān)鍵在于for循環(huán)語句內(nèi),setDaemon()為守護線程方法,在文章頭的其中一篇內(nèi)有提到,我們以當前這個情況為例子。
先是for循環(huán),通過setDaemon()我們在主線程中調(diào)用了t1.setDaemon(),注意for循環(huán)中t1.setDaemon()和t2.setDaemon()設(shè)置的主線程都為當前py文件,當設(shè)置為True時,如果我們的主線程(也就是當前的py文件)結(jié)束了,那么不管t1,t2兩個子線程是否完成,都一并和主線程一起退出。所以輸出結(jié)果如下
>>>
I was listening to 愛情買賣. Thu Apr 17 12:51:45 2014 I was at the 阿凡達! Thu Apr 17 12:51:45 2014 all over Thu Apr 17 12:51:45 2014
所以當主線程執(zhí)行完畢后,子線程也終止,也就不再輸出,如果我們改True為False時,則輸出結(jié)果如下
I was listening to 愛情買賣. Fri Nov 10 20:54:20 2017
I was at the 阿凡達! Fri Nov 10 20:54:20 2017
all over Fri Nov 10 20:54:20 2017
I was listening to 愛情買賣. Fri Nov 10 20:54:21 2017
I was at the 阿凡達! Fri Nov 10 20:54:25 2017
[Finished in 10.1s]
因為改為了False,所以即使主線程結(jié)束了,子線程 也會接著運行,這里特別注意一點,“all over ...” 輸出的位置為結(jié)果中間,也就是說主線程并沒有阻塞!這也是下面介紹的join()方法與setDaemon(False)最大的不同,join()方法會阻塞主線程。
第三種情況(加入join()方法):
import threading
from time import ctime,sleep
def music(func):
for i in range(2):
print "I was listening to %s. %s" %(func,ctime())
sleep(1)
def move(func):
for i in range(2):
print "I was at the %s! %s" %(func,ctime())
sleep(5)
threads = []
t1 = threading.Thread(target=music,args=(u'愛情買賣',))
threads.append(t1)
t2 = threading.Thread(target=move,args=(u'阿凡達',))
threads.append(t2)
if __name__ == '__main__':
for t in threads:
t.start()
for t in threads:
t.join()
print "all over %s" %ctime()
當主線程迅速的執(zhí)行完第一個for循環(huán)時,啟動了兩個線程,于是主線程接著運行,到了第二個for循環(huán),當執(zhí)行t1.join()時,主線程被阻塞了,所以必須等待t1線程執(zhí)行完畢才能接著下一步,接著再執(zhí)行t2.join()同理。因此執(zhí)行結(jié)果會如下
>>>
I was listening to 愛情買賣. Thu Apr 17 13:04:11 2014 I was at the 阿凡達! Thu Apr 17 13:04:11 2014
I was listening to 愛情買賣. Thu Apr 17 13:04:12 2014
I was at the 阿凡達! Thu Apr 17 13:04:16 2014
all over Thu Apr 17 13:04:21 2014
如果我們向之前一樣往執(zhí)行語句里面加入setDaemon(True)
if __name__ == '__main__':
for t in threads:
t.setDaemon(True)
t.start()
for t in threads:
t.join()
print "all over %s" %ctime()
因為t.join()阻塞了主線程,所以主線程不可能跑的比子線程快,所以這里的setDaemon(True)也就可有可無了,執(zhí)行結(jié)果也會想同
I was listening to 愛情買賣. Thu Apr 17 13:11:27 2014I was at the 阿凡達! Thu Apr 17 13:11:27 2014
I was listening to 愛情買賣. Thu Apr 17 13:11:31 2014
I was at the 阿凡達! Thu Apr 17 13:11:32 2014
all over Thu Apr 17 13:11:37 2014
關(guān)鍵在于注意理解t.join()和setDaemon(False)的區(qū)別,以及通過輸出語句的時間對比,體會子進程的執(zhí)行順序。如果理解困難可以先由單個子線程開始,后面再嘗試添加for循環(huán)和多個子線程,同時理解。