python threading-单线程 多线程 主线程 子线程 setDeamon join
python threading-單線程 多線程 主線程 子線程 setDeamon join
- 單線程
- 多線程
- 主線程和子線程
- setDaemon()
- join()
- 測(cè)試多線程下程序運(yùn)行的時(shí)間
- 創(chuàng)建多個(gè)線程
- 優(yōu)化子線程
單線程
用單線程 ,做聽(tīng)音樂(lè)和看電影兩件事兒,首先排一下順序。
import timedef music():for i in range(2):print("I was listening to music. %s" %time.ctime())time.sleep(1)def move():for i in range(2):print("I was at the movies. %s" %time.ctime())time.sleep(5)if __name__=='__main__':music()move()print("all over %s" %time.ctime())輸出結(jié)果:
I was listening to music. Wed Oct 20 15:42:19 2021 I was listening to music. Wed Oct 20 15:42:20 2021 I was at the movies. Wed Oct 20 15:42:21 2021 I was at the movies. Wed Oct 20 15:42:26 2021 all over Wed Oct 20 15:42:31 2021time.sleep(1)是延時(shí)1s的意思。我們先聽(tīng)了一首音樂(lè),通過(guò)for循環(huán)來(lái)控制音樂(lè)的播放了兩次,每首音樂(lè)播放需要1秒鐘,sleep()來(lái)控制音樂(lè)播放的時(shí)長(zhǎng)。接著我們又看了一場(chǎng)電影,每一場(chǎng)電影需要5秒鐘,通過(guò)for循環(huán)看兩遍。在整個(gè)結(jié)束后,輸出當(dāng)前的時(shí)間。
可以發(fā)現(xiàn):整個(gè)代碼只能是先干一件事再干一件事。
用時(shí):開(kāi)始42分19結(jié)束是42分31,總耗時(shí)為12s。
多線程
cpu同時(shí)干多個(gè)活都沒(méi)問(wèn)題的,不需要讓一件事一直占著cpu不放;于是,操作系統(tǒng)就進(jìn)入了多任務(wù)時(shí)代。
python提供了threading模塊來(lái)實(shí)現(xiàn)多線程。可以 引入threadring來(lái)同時(shí)播放音樂(lè)和視頻。
import threading import timedef music():for i in range(2):print("I was listening to music. %s" %time.ctime())time.sleep(1)def move():for i in range(2):print("I was at the movies. %s" %time.ctime())time.sleep(5) ''' 創(chuàng)建了threads數(shù)組,創(chuàng)建線程t1,使用threading.Thread()方法,在這個(gè)方法中調(diào)用music方法target=music,把創(chuàng)建好的線程t1裝到threads數(shù)組中。接著以同樣的方式創(chuàng)建線程t2,并把t2也裝到threads數(shù)組。 ''' threads = [] t1 = threading.Thread(target=music) threads.append(t1) t2 = threading.Thread(target=move) threads.append(t2)if __name__=='__main__':for t in threads:t.setDaemon(True)t.start()print("all over %s" %time.ctime())主線程和子線程
主線程:是執(zhí)行主(main)方法的線程.
子線程:被Thread包含的“方法體”或者“委托”均為子線程
setDaemon()
當(dāng)啟動(dòng)一個(gè)線程時(shí)設(shè)置thread.setDaemon(True),則該線程為守護(hù)線程(也可以稱(chēng)為后臺(tái)線程)。表示該線程是不重要的,進(jìn)程退出時(shí)不需要等待這個(gè)線程執(zhí)行完成。這樣做的意義在于:避免子線程無(wú)限死循環(huán),導(dǎo)致退不出程序,也就是避免了孤兒進(jìn)程的出現(xiàn)。
當(dāng)不設(shè)置或者thread.setDaemon(False)時(shí),主進(jìn)程執(zhí)行結(jié)束時(shí),會(huì)等待線程結(jié)束。
上述程序如果設(shè)置t.setDaemon(False),那么將輸出:
I was listening to music. Wed Oct 20 16:11:27 2021 I was at the movies. Wed Oct 20 16:11:27 2021 all over Wed Oct 20 16:11:27 2021 I was listening to music. Wed Oct 20 16:11:28 2021 I was at the movies. Wed Oct 20 16:11:32 2021可以看到,在主線程進(jìn)行完之后,也就是輸出all over Wed Oct 20 16:11:27 2021之后,還會(huì)繼續(xù)執(zhí)行沒(méi)完成的子線程。
如果設(shè)置setDaemon(True),那么將輸出:
I was listening to music. Wed Oct 20 16:03:27 2021 I was at the movies. Wed Oct 20 16:03:27 2021 all over Wed Oct 20 16:03:27 2021也就是說(shuō),子線程啟動(dòng)后,父線程也繼續(xù)執(zhí)行下去,當(dāng)父線程執(zhí)行完最后一條語(yǔ)句print(“all over %s” %time.ctime())后,沒(méi)有等待子線程,直接就退出了,同時(shí)子線程也一同結(jié)束。
join()
import threading import timedef music():for i in range(2):print("I was listening to music. %s" %time.ctime())time.sleep(1)def move():for i in range(2):print("I was at the movies. %s" %time.ctime())time.sleep(5)threads = [] t1 = threading.Thread(target=music) threads.append(t1) t2 = threading.Thread(target=move) threads.append(t2)if __name__=='__main__':for t in threads:t.setDaemon(True)t.start()for t in threads:t.join()print("all over %s" %time.ctime())運(yùn)行結(jié)果:
I was listening to music. Wed Oct 20 16:21:41 2021 I was at the movies. Wed Oct 20 16:21:41 2021 I was listening to music. Wed Oct 20 16:21:42 2021 I was at the movies. Wed Oct 20 16:21:46 2021 all over Wed Oct 20 16:21:51 2021我們只對(duì)上面的程序加了個(gè)join()方法,用于等待線程終止。join()的作用是,在子線程完成運(yùn)行之前,這個(gè)子線程的父線程將一直被阻塞。
也就是說(shuō),必須等待for循環(huán)里的兩個(gè)進(jìn)程都結(jié)束后,才去執(zhí)行主進(jìn)程。
從執(zhí)行結(jié)果可看到,music 和move 是同時(shí)啟動(dòng)的。
開(kāi)始時(shí)間21分41秒,結(jié)束時(shí)間為21分51秒,總耗時(shí)為10秒。比單線程用時(shí)減少了2秒。
測(cè)試多線程下程序運(yùn)行的時(shí)間
現(xiàn)在把music的sleep()的時(shí)間調(diào)整為5秒。
import threading import timedef music():for i in range(2):print("I was listening to music. %s" %time.ctime())time.sleep(5)def move():for i in range(2):print("I was at the movies. %s" %time.ctime())time.sleep(5)threads = [] t1 = threading.Thread(target=music) threads.append(t1) t2 = threading.Thread(target=move) threads.append(t2)if __name__=='__main__':for t in threads:t.setDaemon(True)t.start()for t in threads:t.join()print("all over %s" %time.ctime()) I was listening to music. Wed Oct 20 16:41:59 2021 I was at the movies. Wed Oct 20 16:41:59 2021 I was listening to music. Wed Oct 20 16:42:04 2021 I was at the movies. Wed Oct 20 16:42:04 2021 all over Wed Oct 20 16:42:09 2021可以看到,最后還是用時(shí)10s。
如果是用單線程的話,用時(shí)將達(dá)到5*4=20s。
創(chuàng)建多個(gè)線程
從上面例子中發(fā)現(xiàn)線程的創(chuàng)建是頗為麻煩的,每創(chuàng)建一個(gè)線程都需要?jiǎng)?chuàng)建一個(gè)tx(t1、t2、…),如果創(chuàng)建的線程多時(shí)候這樣極其不方便。下面對(duì)通過(guò)例子進(jìn)行繼續(xù)改進(jìn):
import threading import timedef music(func):for i in range(2):print("Start music: %s! %s" % (func, time.ctime()))time.sleep(5)def move(func):for i in range(2):print("Start playing: %s! %s" % (func, time.ctime()))time.sleep(5)''' 創(chuàng)建了一個(gè)player()函數(shù),這個(gè)函數(shù)用于判斷播放文件的類(lèi)型。如果是mp3格式的,我們將調(diào)用music()函數(shù),如果是mp4格式的我們調(diào)用move()函數(shù)。哪果兩種格式都不是那么只能告訴用戶你所提供有文件我播放不了 '''def player(name):r = name.split('.')[1]if r == 'mp3':music(name)else:if r == 'mp4':move(name)else:print("ERROR:The format is not recognized!")''' 創(chuàng)建了一個(gè)list的文件列表,注意為文件加上后綴名。然后我們用len(list) 來(lái)計(jì)算list列表有多少個(gè)文件,這是為了幫助我們確定循環(huán)次數(shù)。 '''list = ['jjj.mp3', 'yyy.mp4']threads = []files = range(len(list))''' 通過(guò)一個(gè)for循環(huán),把list中的文件添加到線程中數(shù)組threads[]中。 '''for i in files:t = threading.Thread(target=player, args=(list[i],))threads.append(t)''' 啟動(dòng)threads[]線程組,最后打印結(jié)束時(shí)間。 ''' if __name__ == '__main__':for i in files:threads[i].start()for t in files:threads[i].join()print("all over %s" %time.ctime())運(yùn)行結(jié)果:
Start music: jjj.mp3! Wed Oct 20 17:04:49 2021 Start playing: yyy.mp4! Wed Oct 20 17:04:49 2021 Start playing: yyy.mp4! Wed Oct 20 17:04:54 2021 Start music: jjj.mp3! Wed Oct 20 17:04:54 2021 all over Wed Oct 20 17:04:59 2021其中,split()可以將一個(gè)字符串拆分成兩部分,然后取其中的一部分。也就是說(shuō),判斷l(xiāng)ist[i]里面后綴是mp3還是mp4類(lèi)型的。
>>> x = 'testing.py' >>> s = x.split('.')[1] >>> if s=='py':print(s)py現(xiàn)在向list數(shù)組中添加一個(gè)文件,程序運(yùn)行時(shí)會(huì)自動(dòng)為其創(chuàng)建一個(gè)線程。
優(yōu)化子線程
我們發(fā)現(xiàn)player()用于判斷文件擴(kuò)展名,然后調(diào)用music()和move() ,其實(shí),music()和move()工作是類(lèi)似的,可以改進(jìn)一下,不管什么文件都可以播放。
import threading import time''' 創(chuàng)建player()函數(shù),用于接收f(shuō)ile和t,用于確定要播放的文件及時(shí)長(zhǎng)。 ''' def player(file, t):for i in range(2):print("Start playing: %s! %s" % (file, time.ctime()))time.sleep(t)''' 字典list ,用于定義要播放的文件及時(shí)長(zhǎng)(秒),通過(guò)字典的items()方法來(lái)循環(huán)的取file和t,取到的這兩個(gè)值用于創(chuàng)建線程。 '''list = {'jjj.mp3': 3, 'yyy.mp4': 5, 'mmm.mp3': 4}threads = []files = range(len(list))for file, t in list.items():tx = threading.Thread(target=player, args=(file, t))threads.append(tx)if __name__ == '__main__':for i in files:threads[i].start()for t in files:threads[i].join()print("all over %s" %time.ctime())運(yùn)行結(jié)果:
Start playing: jjj.mp3! Wed Oct 20 17:50:43 2021 Start playing: yyy.mp4! Wed Oct 20 17:50:43 2021 Start playing: mmm.mp3! Wed Oct 20 17:50:43 2021 Start playing: jjj.mp3! Wed Oct 20 17:50:46 2021 Start playing: mmm.mp3! Wed Oct 20 17:50:47 2021 Start playing: yyy.mp4! Wed Oct 20 17:50:48 2021 all over Wed Oct 20 17:50:51 2021總結(jié)
以上是生活随笔為你收集整理的python threading-单线程 多线程 主线程 子线程 setDeamon join的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: signature=08653706de
- 下一篇: 设备管理器android感叹号,设备管理