python多線程講解-創(chuàng)新互聯(lián)

目錄

成都創(chuàng)新互聯(lián)憑借專業(yè)的設(shè)計(jì)團(tuán)隊(duì)扎實(shí)的技術(shù)支持、優(yōu)質(zhì)高效的服務(wù)意識和豐厚的資源優(yōu)勢,提供專業(yè)的網(wǎng)站策劃、網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作、網(wǎng)站優(yōu)化、軟件開發(fā)、網(wǎng)站改版等服務(wù),在成都十余年的網(wǎng)站建設(shè)設(shè)計(jì)經(jīng)驗(yàn),為成都近1000家中小型企業(yè)策劃設(shè)計(jì)了網(wǎng)站。

什么是線程?

并發(fā)與并行

什么是GIL?

為什么要使用多線程?

多線程實(shí)例

守護(hù)線程

多線程共享全局變量

互斥鎖Lock

RLock遞歸鎖

信號量


python多線程是一個(gè)非常重要的知識點(diǎn),接下來對該部分內(nèi)容進(jìn)行梳理。

什么是線程?

線程也叫輕量級進(jìn)程,是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,它被包涵在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)兒在運(yùn)行中必不可少的資源,但它可與同屬一個(gè)進(jìn)程的其他線程共享進(jìn)程所擁有的全部資源。一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程,同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。

并發(fā)與并行

并發(fā)是快速交替輪換執(zhí)行(線程看起來是同時(shí)在運(yùn)行,實(shí)際上是一個(gè)線程遇到耗時(shí)的IO等操作時(shí)將此線程掛起釋放GIL全局解釋器鎖轉(zhuǎn)而執(zhí)行其他線程的過程,這個(gè)過程輪換的非??欤院暧^上看起來就像是多個(gè)線程同時(shí)運(yùn)行),并行是同一時(shí)間同時(shí)運(yùn)行(進(jìn)程可以做到并行運(yùn)行,充分利用多核cpu的優(yōu)勢)

什么是GIL?

GIL全稱是全局解釋器鎖,為了解決多線程之間數(shù)據(jù)完整性和狀態(tài)同步而產(chǎn)生的一把鎖。它保證了在同一時(shí)刻只有一個(gè)線程執(zhí)行,當(dāng)其他線程需要運(yùn)行時(shí)必須先拿到這把鎖才能執(zhí)行,這就保證了數(shù)據(jù)的完整性和狀態(tài)的同步。關(guān)于GIL的更多知識可以參考這篇博客。

為什么要使用多線程?

線程在程序中是獨(dú)立的、并發(fā)的執(zhí)行流。與分隔的進(jìn)程相比,進(jìn)程中線程之間的隔離程度要小,它們共享內(nèi)存、文件句柄?和其他進(jìn)程應(yīng)有的狀態(tài)。
因?yàn)榫€程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。進(jìn)程在執(zhí)行過程之中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大的提升了程序的運(yùn)行效率。線程比進(jìn)程具有更高的性能,這是由于同一個(gè)進(jìn)程中的線程都有共性,多個(gè)線程共享一個(gè)進(jìn)程的虛擬空間。線程的共享環(huán)境包括進(jìn)程代碼段、進(jìn)程的共有數(shù)據(jù)等,利用這些共享的數(shù)據(jù),線程之間很容易實(shí)現(xiàn)通信。操作系統(tǒng)在創(chuàng)建進(jìn)程時(shí),必須為改進(jìn)程分配獨(dú)立的內(nèi)存空間,并分配大量的相關(guān)資源,但創(chuàng)建線程則簡單得多。因此,使用多線程來實(shí)現(xiàn)并發(fā)比使用多進(jìn)程的性能高得要多。

操作系統(tǒng)在創(chuàng)建進(jìn)程時(shí),需要為該進(jìn)程重新分配系統(tǒng)資源,但創(chuàng)建線程的代價(jià)則小得多。因此使用多線程來實(shí)現(xiàn)多任務(wù)并發(fā)執(zhí)行比使用多進(jìn)程的效率。python語言內(nèi)置了多線程功能支持,而不是單純地作為底層操作系統(tǒng)的調(diào)度方式,從而簡化了python的多線程編程。

多線程實(shí)例

普通創(chuàng)建方式:

打印結(jié)果如下:

通過打印的順序可以發(fā)現(xiàn),多線程是異步非阻塞的(首先打印task2,再打印task3,最后等待task1執(zhí)行結(jié)束后再結(jié)束主線程),主線程的結(jié)束并沒有強(qiáng)制結(jié)束子線程,是等待子線程結(jié)束后才結(jié)束主線程。?當(dāng)我們需要某個(gè)線程執(zhí)行完成再往下面執(zhí)行,可以手動添加join()方法阻塞主線程,這樣主線程會等待join的線程執(zhí)行完成再往下執(zhí)行,下面守護(hù)線程會講到j(luò)oin()方法。

自定義線程------繼承threading.Thread類實(shí)現(xiàn)自定義線程,其本質(zhì)是重構(gòu)Thread類的run方法:

打印結(jié)果:

t.start()方法在執(zhí)行的時(shí)候會自動調(diào)用run()方法,所以在自定義線程的時(shí)候只需要重寫__init__方法和run()方法即可,__init__方法負(fù)責(zé)接收參數(shù),這些參數(shù)最后會傳入run()方法中,根據(jù)需要實(shí)現(xiàn)自定義功能。

守護(hù)線程

這里使用setDaemon(True)把所有的子線程都變成了主線程的守護(hù)線程,因此當(dāng)主線程結(jié)束后,子線程也會隨之結(jié)束,所以當(dāng)主線程結(jié)束后,整個(gè)程序就退出了。

把線程t1設(shè)置成守護(hù)線程,意味著不管t1線程有沒有運(yùn)行完成,只要主線程運(yùn)行結(jié)束了,t1線程也會被迫結(jié)束,看一下打印結(jié)果:

t2、t3線程運(yùn)行結(jié)束后主線程也隨之運(yùn)行到結(jié)尾,此時(shí)t1線程還處于sleep狀態(tài),但是由于設(shè)置成守護(hù)線程了,此時(shí)主線程關(guān)閉,t1線程也被迫結(jié)束,整個(gè)程序退出。

但是在這種情況下,可以使用join()方法手動阻塞當(dāng)前線程,看如下代碼:

使用t1.join()阻塞當(dāng)前進(jìn)程,當(dāng)主線程運(yùn)行到t1.join()的時(shí)候會被阻塞在此處,直到t1線程運(yùn)行結(jié)束,所以就算t1線程設(shè)置成了守護(hù)線程,主線程也得等到t1線程運(yùn)行完成后才能往下執(zhí)行,然后結(jié)束主線程,退出程序。打印結(jié)果如下:

多線程共享全局變量

一個(gè)進(jìn)程中的多個(gè)線程資源是共享的,看下面這個(gè)例子:

打印結(jié)果如下:

從打印結(jié)果可以看出來,全局的變量在work1中做了加法,在work2中打印num的值時(shí)顯示的是加法運(yùn)行之后的值,說明兩個(gè)work操作的是同一個(gè)變量。從而印證了線程之間的資源是共享的。

雖然有了全局解釋器鎖GIL,但是它不能保證線程數(shù)據(jù)的安全性,當(dāng)多個(gè)線程操作一個(gè)變量的時(shí)候,舉個(gè)例子有個(gè)變量a初始值是1,要對其進(jìn)行a+=1這個(gè)操作可以細(xì)分成兩步,a+1 和a=a+1,比如兩個(gè)線程對a進(jìn)行操作,當(dāng)線程1拿到調(diào)度權(quán)的時(shí)候,對a進(jìn)行a+1操作,此時(shí)線程1交出了調(diào)度權(quán),線程2獲取到的執(zhí)行的機(jī)會,同樣對a進(jìn)行操作,此時(shí)的a仍然是1,因?yàn)榫€程1只是做了加法運(yùn)算還沒有最終把a(bǔ)+1的值賦值給變量a的時(shí)候線程2便拿到了調(diào)度權(quán),所以線程2做了一次完整的a+=1操作,a的值變成了2,這個(gè)時(shí)候線程2交出調(diào)度權(quán),線程1拿到調(diào)度權(quán)繼續(xù)運(yùn)行最后的賦值操作,a的值為2。此時(shí)發(fā)現(xiàn)a做了兩次加法操作,但是最終的值是2,這便產(chǎn)生了臟數(shù)據(jù)。為了解決這個(gè)問題引入線程鎖。

互斥鎖Lock

為了解決線程數(shù)據(jù)不安全性,引入互斥鎖概念,看如下例子:

在修改變量n的時(shí)候,先lock.acquire()給線程上鎖,這樣其他的線程便拿不到這個(gè)資源,當(dāng)完成對數(shù)據(jù)的操作后,lock.release()解鎖,其他線程便可以操作變量n,這樣便解決了原子性問題。

打印結(jié)果:使用10個(gè)線程對數(shù)字10000000進(jìn)行減法操作,如期得到最后的結(jié)果1。使用互斥鎖解決了線程數(shù)據(jù)不安全問題,避免了臟數(shù)據(jù)的產(chǎn)生。

RLock遞歸鎖

還有一種鎖RLock遞歸鎖,用法與lock鎖一樣,不同的是它支持嵌套,在多個(gè)鎖沒有釋放的時(shí)候,一般會使用RLock類。

信號量

用一句話說,信號量就是為了控制線程的并發(fā)數(shù)。

例如餐桌有三個(gè)位置,但是有10個(gè)人同時(shí)就餐,這時(shí)候就需要信號量參與保證餐桌上只有三個(gè)人,也就是線程的并發(fā)數(shù)始終是3。

觀察打印結(jié)果發(fā)現(xiàn),只有三個(gè)線程在并發(fā)運(yùn)行,其他線程需要等待線程釋放之后才參與進(jìn)來。線程池也是為了控制線程的并發(fā)數(shù)。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

當(dāng)前文章:python多線程講解-創(chuàng)新互聯(lián)
文章URL:http://www.bm7419.com/article20/dpcgco.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)、品牌網(wǎng)站建設(shè)、品牌網(wǎng)站制作關(guān)鍵詞優(yōu)化、云服務(wù)器動態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站網(wǎng)頁設(shè)計(jì)