版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第八章
多線程Python程序設(shè)計(jì)01線程概述02使用Python實(shí)現(xiàn)多線程03綜合案例:基于多線程的爬蟲應(yīng)用04本章回顧01線程概述1.什么是進(jìn)程進(jìn)程是操作系統(tǒng)資源分配和調(diào)度的基本單位。計(jì)算機(jī)使用時(shí)多個(gè)同時(shí)運(yùn)行的軟件程序,程序代碼存于磁盤,加載到內(nèi)存由CPU執(zhí)行,運(yùn)行中可能與外設(shè)交互、產(chǎn)生數(shù)據(jù),操作系統(tǒng)將運(yùn)行程序封裝成進(jìn)程并按調(diào)度算法切換執(zhí)行,可按“Ctrl+Alt+Delete”打開任務(wù)管理器查看進(jìn)程。01線程概述2.什么是線程在早期的操作系統(tǒng)中并沒有線程的概念,進(jìn)程是擁有資源和獨(dú)立運(yùn)行的最小單位,也是程序執(zhí)行的最小單位。后來隨著計(jì)算機(jī)行業(yè)的發(fā)展,程序功能的設(shè)計(jì)越來越復(fù)雜,而某些活動(dòng)隨著時(shí)間的推移會(huì)被阻塞,此時(shí)就想到能否將這些應(yīng)用程序分解成更細(xì)粒度的實(shí)體,并且這些細(xì)粒度的執(zhí)行實(shí)體可以共享進(jìn)程的地址空間,所以就出現(xiàn)了線程的概念。線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,可以看做是輕量級的進(jìn)程,線程之間切換的開銷小,所以線程的創(chuàng)建、銷毀、調(diào)度性能遠(yuǎn)遠(yuǎn)優(yōu)于進(jìn)程。01線程概述3.進(jìn)程和線程的區(qū)別進(jìn)程和線程分工明確,進(jìn)程有主線程,負(fù)責(zé)分配管理資源,線程負(fù)責(zé)CPU調(diào)度運(yùn)算,是CPU切換時(shí)間片最小單位。一個(gè)進(jìn)程多個(gè)線程,線程共享進(jìn)程堆和方法區(qū)資源,各有自己的程序計(jì)數(shù)器和棧區(qū)域。01線程概述方法區(qū):用來存放加載的類、常量等信息。堆:是進(jìn)程中最大的一塊內(nèi)存空間。棧:用于存儲(chǔ)該線程的局部變量(私有的)和棧禎。計(jì)數(shù)器:一塊內(nèi)存區(qū)域,用來記錄線程當(dāng)前要執(zhí)行的指令地址。關(guān)于進(jìn)程與線程的區(qū)別總結(jié)如右圖所示。多線程相關(guān)概念1.什么是多線程多線程是指程序中包含多個(gè)執(zhí)行流,即在一個(gè)程序中可以同時(shí)運(yùn)行多個(gè)不同的線程來執(zhí)行不同的任務(wù)。舉一個(gè)生活中的例子,如果你吃完水果再看電視就是單線程,而一邊吃水果一邊看電視就是多線程。在擁有多核的機(jī)器上,使用多線程技術(shù),可以明顯提升系統(tǒng)的執(zhí)行效率。多線程相關(guān)概念2.并發(fā)與多線程多線程可以實(shí)現(xiàn)任務(wù)并發(fā)執(zhí)行,并發(fā)是指同一個(gè)時(shí)間段內(nèi)多個(gè)任務(wù)同時(shí)都在執(zhí)行,并且都沒有執(zhí)行結(jié)束,并發(fā)任務(wù)強(qiáng)調(diào)在一個(gè)時(shí)間段內(nèi)同時(shí)執(zhí)行,而一個(gè)時(shí)間段由多個(gè)單位時(shí)間累積而成,所以說并發(fā)的多個(gè)任務(wù)在單位時(shí)間內(nèi)不一定同時(shí)在執(zhí)行。多線程并發(fā)執(zhí)行過程中需要注意線程安全的問題,即當(dāng)多個(gè)線程同時(shí)操作共享變量時(shí),會(huì)出現(xiàn)某個(gè)線程更新共享變量的值,但是其它線程獲取到的是共享變量沒有被更新之前的值,這將導(dǎo)致數(shù)據(jù)不準(zhǔn)確,可以使用多線程同步和加鎖解決此問題。多線程相關(guān)概念3.線程的生命周期當(dāng)線程被創(chuàng)建并啟動(dòng)以后,它既不是一啟動(dòng)就進(jìn)入執(zhí)行狀態(tài),也不是一直處于執(zhí)行狀態(tài),其要經(jīng)過新建(New)、就緒(Runnable)、運(yùn)行(Running)、阻塞(Blocked)和死亡(Dead)5種狀態(tài),這5種狀態(tài)也叫線程的生命周期,如下圖所示。多線程相關(guān)概念(1)新建狀態(tài)當(dāng)使用新建線程的方法建立一個(gè)線程后,該線程對象處于新建狀態(tài),注意此時(shí)線程未被啟動(dòng)。(2)就緒狀態(tài)當(dāng)處于新建狀態(tài)的線程,通過調(diào)用開始啟動(dòng)線程方法進(jìn)入到就緒狀態(tài),此時(shí)線程已經(jīng)被啟動(dòng),具備了運(yùn)行條件,正在等待被分配CPU資源。簡單理解就是處于就緒狀態(tài)的線程已經(jīng)做好了運(yùn)行準(zhǔn)備,等獲取到CPU資源后就可以被運(yùn)行。(3)運(yùn)行狀態(tài)就緒態(tài)線程獲CPU資源進(jìn)入運(yùn)行態(tài)。單CPU時(shí)某時(shí)刻僅一個(gè)線程運(yùn)行,多CPU時(shí)可多線程并行。運(yùn)行線程按調(diào)度策略和優(yōu)先級調(diào)度,不會(huì)一直占CPU。運(yùn)行態(tài)線程時(shí)間片內(nèi)正常結(jié)束進(jìn)死亡態(tài),否則回就緒態(tài)。多線程相關(guān)概念(4)阻塞狀態(tài)當(dāng)處于運(yùn)行狀態(tài)的線程遇到某些情況就會(huì)進(jìn)入到阻塞狀態(tài),如:調(diào)用了sleep()方法主動(dòng)放棄其所占用的處理器資源。等待I/O流的輸入輸出。等待網(wǎng)絡(luò)資源。試圖獲得一個(gè)鎖對象,但該鎖對象正被其它線程所持有。等待某個(gè)通知。當(dāng)引起阻塞的原因消除后,線程就會(huì)重新轉(zhuǎn)入到就緒狀態(tài)。(5)死亡狀態(tài)線程生命周期的最后一個(gè)階段就是死亡狀態(tài),進(jìn)入死亡狀態(tài)的原因主要可總結(jié)如下:正常運(yùn)行的線程完成了全部的工作。線程拋出未捕獲的異常。線程被強(qiáng)制性終止。需要注意的是主線程死亡,并不意味著所有線程全部死亡。也就是說,主線程的死亡,不會(huì)影響子線程繼續(xù)執(zhí)行,反之亦然。02使用Python實(shí)現(xiàn)多線程Python3的_thread庫和threading庫支持線程,重點(diǎn)介紹threading庫多線程實(shí)現(xiàn)。Python的GIL使同一時(shí)間僅一個(gè)線程能用CPU,其多線程雖不能提高CPU利用率,但能提高程序I/O(磁盤和網(wǎng)絡(luò)讀寫)訪問速度。使用threading實(shí)現(xiàn)多線程1.普通方式實(shí)現(xiàn)多線程接下來我們可以先定義2個(gè)函數(shù),然后模擬多線程的實(shí)現(xiàn)過程,如右圖所示。使用threading實(shí)現(xiàn)多線程在上面代碼中,函數(shù)study1()和study2()被稱為線程函數(shù),函數(shù)內(nèi)的代碼就是線程要執(zhí)行的內(nèi)容;在創(chuàng)建Thread類實(shí)例的時(shí)候,需要將線程函數(shù)的函數(shù)名傳給target參數(shù);線程實(shí)例創(chuàng)建完之后,需要使用start()方法啟動(dòng)線程,這時(shí)study1()和study2()函數(shù)內(nèi)的代碼才會(huì)被執(zhí)行,運(yùn)行結(jié)果如下圖所示。使用threading實(shí)現(xiàn)多線程從上圖中可以看出,多線程程序執(zhí)行順序不定。Thread類創(chuàng)建的是子線程,程序默認(rèn)啟動(dòng)主線程,主線程從程序首行、子線程從線程函數(shù)首行執(zhí)行,子線程啟動(dòng)后有兩個(gè)線程。線程執(zhí)行時(shí)間由CPU調(diào)度定。執(zhí)行sleep()函數(shù)線程阻塞,結(jié)束后就緒等待調(diào)度,線程函數(shù)執(zhí)行順序不確定。使用threading實(shí)現(xiàn)多線程2.自定義線程自定義線程就是自己定義一個(gè)類,繼承自threading.Thread類,然后重寫其中的run()函數(shù),舉例如右圖所示。使用threading實(shí)現(xiàn)多線程在上述代碼中,我們定義了一個(gè)MyThread類繼承自threading.Thread類,然后重寫了構(gòu)造方法和run()方法。在main()函數(shù)中,我們對自定義的線程MyThread進(jìn)行了實(shí)例化,然后使用其start()函數(shù)啟動(dòng)線程,啟動(dòng)之后就會(huì)運(yùn)行子線程中的run()函數(shù),運(yùn)行結(jié)果如右圖所示。使用threading實(shí)現(xiàn)多線程上頁代碼中的兩個(gè)線程是同時(shí)運(yùn)行的,其運(yùn)行結(jié)果很混亂,如果我們想讓一個(gè)先運(yùn)行,一個(gè)后運(yùn)行,可以使用join()方法實(shí)現(xiàn),其會(huì)一直等待對應(yīng)線程結(jié)束后才運(yùn)行下一個(gè)線程,如右圖所示使用threading實(shí)現(xiàn)多線程從上圖中可以看出,其是按照順序執(zhí)行的,線程1完成所有工作之后,線程2才開始工作。默認(rèn)情況下join()函數(shù)會(huì)一直等待對應(yīng)線程結(jié)束然后進(jìn)入下一個(gè)線程,但是我們也可以通過其timeout參數(shù)設(shè)置指定時(shí)間(單位是秒),如“t.join(timeout=1)”。使用threading實(shí)現(xiàn)多線程3.threading.Thread類常用屬性和方法上面介紹了實(shí)現(xiàn)多線程的兩種方式,threading.Thread類中還有一些屬性和方法可以幫助我們獲取線程的一些信息,如獲取線程的名稱可以通過屬性name和getName(),如右圖所示。使用threading實(shí)現(xiàn)多線程為了方便大家記憶,現(xiàn)將threading.Thread類的常用屬性和方法總結(jié)如下表所示。線程鎖多線程開發(fā)特性:原子性:保證數(shù)據(jù)一致、解決線程安全問題,操作要么全執(zhí)行不被打斷,要么不執(zhí)行??梢娦裕憾嗑€程訪問同一變量,一個(gè)線程修改值,其他線程能馬上看到。有序性:程序按代碼先后順序執(zhí)行線程鎖但有時(shí)在使用多線程時(shí),會(huì)違背其中的特性,接下來我們定義一個(gè)制作桌子的線程,然后啟動(dòng)3個(gè)線程來工作,如下圖所示。線程鎖上述代碼運(yùn)行結(jié)果從左圖中可以看出,需20個(gè)桌子,但運(yùn)行結(jié)果序號(hào)超20(違背多線程特性),因3線程同時(shí)工作,一線程改值其他線程不能及時(shí)知曉??山柚€程鎖機(jī)制,鎖制作椅子和打印結(jié)果,避免CPU使用權(quán)被系統(tǒng)切換線程鎖2.線程鎖的使用threading模塊提供的Lock()函數(shù)可以提供線程鎖服務(wù),一旦線程獲得鎖,其他試圖獲取鎖的線程將被阻塞等待。給線程加鎖主要分為以下3步:①使用threading.Lock()初始化鎖。②使用Lock.acquire()獲取鎖。③使用Lock.rease()釋放鎖。線程鎖接下來對“做桌子”代碼實(shí)現(xiàn)加鎖服務(wù),如下圖所示。線程鎖加鎖之后的運(yùn)行結(jié)果如右圖所示(不會(huì)再出現(xiàn)圖8-8中超出序號(hào)的情況)。案例【案例描述】無論是在工作中還是學(xué)習(xí)過程中,經(jīng)常需要對文件或文件夾進(jìn)行復(fù)制,如從朋友那里復(fù)制電影、歌曲、小說等;從同事那里復(fù)制項(xiàng)目資源等。本案例我們分別使用單線程和多線程進(jìn)行視頻文件夾的復(fù)制,并對比其效率。【案例要求】在D盤中有一個(gè)文件夾videos,文件夾中是一些視頻文件,如右圖所示。請分別使用單線程和多線程的方式將其備份到D盤下的videosbak1和videosbak2文件夾下(文件夾已存在),并計(jì)算耗時(shí)。案例【代碼1】以單線程的方式復(fù)制文件【代碼2】以多線程的方式復(fù)制文件案例【運(yùn)行結(jié)果】以單線程和多線程的方式復(fù)制文件的運(yùn)行結(jié)果對比如圖1所示。從圖1中可以看出,以多線程的方式復(fù)制文件的運(yùn)行效率是優(yōu)于單線程的,說明在進(jìn)行I/O文件訪問時(shí),多線程方案還是能提高程序的執(zhí)行效率的。這里由于文件比較少,對比結(jié)果不是特別明顯,如果處理大量文件時(shí)對比會(huì)更明顯。03綜合案例項(xiàng)目分析:項(xiàng)目背景:微信、QQ等社交軟件興起,網(wǎng)絡(luò)聊天成生活一部分,年輕人愛用表情包,其省事便利,能降成本、調(diào)氛圍、更好表達(dá)想法,“斗圖”時(shí)還考驗(yàn)表情包庫存。項(xiàng)目需求:人們希望短時(shí)間獲海量表情包,常使用網(wǎng)絡(luò)爬蟲,Python類庫豐富,是爬蟲首選工具,本項(xiàng)目爬取一個(gè)表情包網(wǎng)站(下圖)。運(yùn)行程序后,預(yù)期效果是電腦中會(huì)出現(xiàn)一個(gè)文件夾,文件夾中是下載后的表情包,并且表情包以其在網(wǎng)站中的標(biāo)題命名。03綜合案例項(xiàng)目實(shí)現(xiàn)思路:爬蟲分網(wǎng)頁下載、解析、數(shù)據(jù)保存三階段,本項(xiàng)目適用。(1)網(wǎng)頁下載:分析網(wǎng)頁網(wǎng)址變化規(guī)律,此網(wǎng)站頁碼動(dòng)態(tài)拼接在url結(jié)尾,主要用6.3.2介紹過的requests庫。(2)網(wǎng)頁解析:對下載得到的html內(nèi)容解析,找表情包標(biāo)題、鏈接等數(shù)據(jù),主要用6.3.2的BeautifulSoup庫。(3)數(shù)據(jù)保存:通過解析獲取圖片url后,借瀏覽器request請求獲圖片二進(jìn)制內(nèi)容,用file對象寫入保存。此外,本案例還用單線程和多線程爬蟲并對比耗時(shí)。單線程爬取表情包【核心知識(shí)點(diǎn)】①函數(shù)定義與調(diào)用;②Requests庫使用;③BeautifulSoup庫使用;④os、random等模塊使用?!竞诵牧鞒獭竣僦付ù鎴D文件夾,無則創(chuàng)建;②指定待爬取網(wǎng)頁url;③設(shè)多個(gè)瀏覽器User-Agent列表,模擬隨機(jī)選一個(gè)獲取headers;④用獲取的headers和requests庫獲取html內(nèi)容;⑤用BeautifulSoup庫依html內(nèi)容獲取img標(biāo)簽的標(biāo)題和圖片鏈接信息;⑥根據(jù)圖片鏈接信息獲取二進(jìn)制內(nèi)容,以標(biāo)題命名后保存到指定文件夾(循環(huán)保存)單線程爬取表情包單線程爬取表情包運(yùn)行代碼之后,發(fā)現(xiàn)E盤多了一個(gè)名為“bqb”的文件夾,如下圖所示。多線程爬取表情包使用多線程實(shí)現(xiàn)爬蟲的流程與單線程基本類似,只是需要借助threading模塊和queue隊(duì)列模塊,關(guān)于隊(duì)列我們以前沒有接觸過,這里簡單介紹一下。1.queue模塊介紹在Python中,多個(gè)線程之間的數(shù)據(jù)是共享的,多個(gè)線程進(jìn)行數(shù)據(jù)交換的時(shí)候,為了能確保數(shù)據(jù)的安全性和一致性,就可以使用隊(duì)列。Python中的queue模塊實(shí)現(xiàn)了隊(duì)列,其提供了同步的、線程安全的隊(duì)列類,包括先入先出隊(duì)列(Queue)、后入先出隊(duì)列(LifoQueue)和優(yōu)先級隊(duì)列(PriorityQueue)。queue模塊的常用方法可總結(jié)如下表所示。多線程爬取表情包多線程爬取表情包其中使用get([block[,timeout]])方法從隊(duì)列中獲取任務(wù),主要流程如下:①嘗試獲取互斥鎖。②如果此時(shí)隊(duì)列為空,則wait等待生產(chǎn)者線程添加數(shù)據(jù)。③get到任務(wù)后,會(huì)調(diào)用self.not_full.notify()通知生產(chǎn)者線程,隊(duì)列可以添加元素了。④釋放互斥鎖。使用put(item)向隊(duì)列中添加任務(wù),主要流程如下:①申請獲得互斥鎖。②獲得后,如果隊(duì)列未滿,則向隊(duì)列中添加數(shù)據(jù),并通知notify其它阻塞的某個(gè)線程,喚醒等待獲取require互斥鎖。③如果隊(duì)列已滿,則會(huì)wait等待,最后處理完成后釋放互斥鎖。多線程爬取表情包2案例實(shí)現(xiàn)【核心知識(shí)點(diǎn)】①函數(shù)的定義與調(diào)用。②Requests庫的使用。③BeautifulSoup庫的使用。④os、random等模塊的使用。⑤threading線程模塊的使用。⑥queue隊(duì)列模塊的使用。同樣是下載3頁表情包,單線程耗時(shí)186秒,而多線程只需要7秒,效率較單線程高了很多。如右圖所示。多線程爬取表情包多線程爬取表情包多線程爬取表情包上述代碼的運(yùn)行結(jié)果如下圖所示。本章回顧1.【多選】以下關(guān)于進(jìn)程和線程的描述正確的有()。A.進(jìn)程是操作系統(tǒng)資源分配的基本單位B.線程是CPU調(diào)度的最小單位C.每個(gè)進(jìn)程都有獨(dú)立的內(nèi)存空間D.同一進(jìn)程中的線程可以共享內(nèi)存空間2.【多選】以下關(guān)于線程的生命周期描述正確的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2023年年北京市各區(qū)初三語文一模分類試題匯編 - 作文
- 擋環(huán)夾具課程設(shè)計(jì)
- 2024商業(yè)合同范文
- 聯(lián)想物流倉庫課程設(shè)計(jì)
- 模電課程設(shè)計(jì)全部
- 2024解除勞動(dòng)合同證明
- 購房網(wǎng)簽合同(2篇)
- 人教版插畫大全課程設(shè)計(jì)
- 礦井地下開采課程設(shè)計(jì)
- DB11∕T 310-2021 數(shù)字化城市管理信息系統(tǒng)技術(shù)要求
- 2024年浙江中煙工業(yè)限責(zé)任公司公開招聘136人高頻難、易錯(cuò)點(diǎn)500題模擬試題附帶答案詳解
- GB/T 5510-2024糧油檢驗(yàn)谷物及制品脂肪酸值的測定
- 小學(xué)勞動(dòng)教育一年級下冊第二單元第3課《削果皮》課件
- GB/T 22838.6-2024卷煙和濾棒物理性能的測定第6部分:硬度
- 第三單元數(shù)一數(shù)與乘法《兒童樂園》(教學(xué)設(shè)計(jì))-2024-2025學(xué)年北師大版數(shù)學(xué)二年級上冊
- 部編2024版歷史七年級上冊第三單元《第13課 東漢的興衰》教案
- 英語雅思8000詞匯表
- 2024年小工廠入股合作協(xié)議書范文模板
- 2024人教版道法七年級上冊第二單元:成長的時(shí)空大單元整體教學(xué)設(shè)計(jì)
- 職業(yè)技能大賽-網(wǎng)站設(shè)計(jì)與開發(fā)競賽理論知識(shí)題庫(附參考答案)
- 教科版二年級上冊期中檢測科學(xué)試卷
評論
0/150
提交評論