Python爬蟲第六天:進(jìn)程-線程安全-互斥鎖-同步異步-隊列-生產(chǎn)者消費(fèi)者模型-協(xié)程

內(nèi)容簡述:

? ? ?一:初始線程和進(jìn)程

? ? ?二:進(jìn)程和線程的區(qū)別

? ? ?三:線程的調(diào)用方式

? ? ?四:線程安全與線程鎖

? ? ?五:同步和異步

? ? ?六:隊列

? ? ?七:生產(chǎn)者和消費(fèi)者模型

? ? ?八:協(xié)程

一:初始線程,進(jìn)程

? ? ? ?看圖說話:

? ????多任務(wù): 操作系統(tǒng)可同時運(yùn)行多個任務(wù),每一個程序內(nèi)存都是獨(dú)立的? ? ?

????????一邊瀏覽器上網(wǎng),一邊看電影,一邊打開WORD至少3個任務(wù)在運(yùn)行還有????? 后臺運(yùn)行的任務(wù)?? 概述:對于操作系統(tǒng)來說,一個任務(wù)就是一個進(jìn)程.例如:打開一個瀏覽器就是啟動一個瀏覽器進(jìn)程,打開兩word就啟動了兩個word進(jìn)程,有的進(jìn)程還不止同時干一件事,比如Word,它可以同時進(jìn)行打字、拼寫檢查、縮進(jìn)等事情。在一個進(jìn)程內(nèi)部,要同時干多件事,就需要同時運(yùn)行多個“子任務(wù)”,我們把進(jìn)程內(nèi)的這些“子任務(wù)”稱為線程(Thread)

? ? ? 進(jìn)程

???????(Process)是一個正在執(zhí)行的程序,以一個整體的形式暴露給操作系統(tǒng)管理,里面包含對各種資源的調(diào)用,內(nèi)存的管理,網(wǎng)絡(luò)接口的調(diào)用等。。。對各種資源管理的集合。所有在同一個進(jìn)程里的線程是共享同一塊內(nèi)存空間的

? ? ? 線程

? ??????是進(jìn)程中一個獨(dú)立的控制單元,它被包含在進(jìn)程之中。是操作系統(tǒng)最小的調(diào)度單位, 是一串指令的集合。 一個進(jìn)程中至少有一個線程,一個進(jìn)程中可以并發(fā)多個線程,每條線程并行執(zhí)行不同的任務(wù)

? ? ? 備注:

? ? ? ? 進(jìn)程要操作CPU,必須先創(chuàng)建一個線程,一個進(jìn)程中至少有一個線程

二:進(jìn)程和線程的區(qū)別

1-Threads share the address space of the process that created it; processes have their own address space.

線程共享創(chuàng)建它的進(jìn)程的內(nèi)存空間;進(jìn)程有自己的內(nèi)存空間是獨(dú)立的

2-Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.

線程可以直接訪問進(jìn)程的數(shù)據(jù);進(jìn)程擁有父進(jìn)程的數(shù)據(jù)的副本

3-Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.

同一個進(jìn)程的線程之間可以互相訪問;兩個進(jìn)程想通信,須通過一個中間代理來實(shí)現(xiàn)

4-New threads are easily created; new processes require duplication of the parent process.

創(chuàng)建新線程很容易;創(chuàng)建新進(jìn)程需要復(fù)制父進(jìn)程。

5-Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.

一個線程可以控制和操作同一進(jìn)程里的其他線程;進(jìn)程只能操作子進(jìn)程

6-Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.

對主線程的更改(取消、優(yōu)先級更改等)可能會影響進(jìn)程中其他線程的行為;對父進(jìn)程的更改不會影響子進(jìn)程。

三:線程的調(diào)用方式

? ??????1-函數(shù)式調(diào)用

? ??????2-繼承式調(diào)用

四:線程安全與線程鎖

? ??????多線程中,所有變量都由所有線程共享。所以任何一個變量都可以被任意一個線程修改,因此,線程之間共享數(shù)據(jù)最大的危險在于多個線程同時修改一個變量,造成數(shù)據(jù)混亂問題。

? ? ????解決方式:線程鎖(互斥鎖)

? ?互斥鎖

? ? ? ??當(dāng)多個線程幾乎同時修改某一個共享數(shù)據(jù)的時候,需要進(jìn)行同步控制

????????線程同步能夠保證多個線程安全訪問競爭資源,最簡單的同步機(jī)制是引入互斥鎖。

????????互斥鎖為資源引入一個狀態(tài):鎖定/非鎖定。

????????某個線程要更改共享數(shù)據(jù)時,先將其鎖定,此時資源的狀態(tài)為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態(tài)變成“非鎖定”,其他的線程才能再次鎖定該資源?;コ怄i保證了每次只有一個線程進(jìn)行寫入操作,從而保證了多線程情況下數(shù)據(jù)的正確性。

? ??????hreading模塊中定義了Lock類,可以方便的處理鎖定:

????????lock= threading.Lock()??????#創(chuàng)建鎖

? ? ????lock.acquire([blocking])?????#鎖定

? ? ????lock.release()? ? ? ? ? ? ? ? ? ?#釋放

其中,鎖定方法acquire可以有一個blocking參數(shù)。

如果設(shè)定blocking為True,則當(dāng)前線程會堵塞,直到獲取到這個鎖為止(默認(rèn))

如果設(shè)定blocking為False,則當(dāng)前線程不會堵塞

上鎖解鎖過程

當(dāng)一個線程調(diào)用鎖的acquire()方法獲得鎖時,鎖就進(jìn)入“l(fā)ocked”狀態(tài)。每次只有一個線程可以獲得鎖。如果此時另一個線程試圖獲得這個鎖,該線程就會變?yōu)椤癰locked”狀態(tài),稱為“阻塞”,直到擁有鎖的線程調(diào)用鎖的release()方法釋放鎖之后,鎖進(jìn)入“unlocked”狀態(tài)。線程調(diào)度程序從處于同步阻塞狀態(tài)的線程中選擇一個來獲得鎖,并使得該線程進(jìn)入運(yùn)行(running)狀態(tài)。

小結(jié):

????鎖的優(yōu)點(diǎn):確保了某段關(guān)鍵代碼只能由一個線程從頭到尾完整地執(zhí)行

????鎖的缺點(diǎn):

? ? ? ? 1- 阻止了多線程并發(fā)執(zhí)行,包含鎖的某段代碼實(shí)際上只能以單線程模式執(zhí)行,效率降低。????????

? ? ????2-由于可以存在多個鎖不同的線程持有不同的鎖,并試圖獲取對方持有鎖時,可能會造成死鎖

五:同步和異步

????同步:

????????????協(xié)同步調(diào),按預(yù)定的先后次序進(jìn)行運(yùn)行。如:買票排隊。

????????????多任務(wù),多個任務(wù)之間執(zhí)行的時候要求有先后順序,必須一個先執(zhí)行完成之后,另一個才能繼續(xù)執(zhí)行,?只有一個主線。簡言之,同步意味著有序

????異步:

????????????一方的動作不用等另一方動作結(jié)果。如:不同窗口買票。

????????????多任務(wù),?多個任務(wù)之間執(zhí)行沒有先后順序,可以同時運(yùn)行,執(zhí)行的先后順序不會有什么影響,存在的多條運(yùn)行主線。簡言之,異步意味著無序。

六:隊列

?1.隊列:先進(jìn)先出? ? ? ?棧:先進(jìn)后出

? ? Python的Queue模塊中提供了同步的、線程安全的隊列類,包括FIFO(先進(jìn)先出)隊列Queue,LIFO(先進(jìn)后出)隊列LifoQueue,和優(yōu)先級隊列PriorityQueue。這些隊列都實(shí)現(xiàn)了鎖原語(原子性,即要么全做,要么全不做),能夠在多線程中直接使用??梢允褂藐犃衼韺?shí)現(xiàn)線程間的同步。

? ? 相當(dāng)于有順序的容器,那為啥要有隊列?

? ? 列表和隊列的根本區(qū)別是:取出數(shù)據(jù)后數(shù)據(jù)還在不在容器里。

? ??class?queue.Queue(maxsize=0)? ? ? ? ? ? ? ? ? #先進(jìn)先出

? ??class?queue.LifoQueue(maxsize=0) ????????????#last in fisrt out? 先進(jìn)后出

? ??class?queue.PriorityQueue(maxsize=0)? ?????#存儲數(shù)據(jù)時可設(shè)置優(yōu)先級的隊列

?2.Queue的簡要說明

? ? ? ? put():添加數(shù)據(jù)到隊列中

? ?????????????queue.Queue.put(item,?block=True,?timeout=None)

? ? ? ? get():從隊列中取數(shù)據(jù)

? ? ? ? ? ? ? ? queue.Queue.get(block=True,timeout=None)

????????qsize():判斷隊列中是否有數(shù)據(jù)

????????empty():判斷隊列是否為空。如果為空返回True

? ? ? ? full():如果滿了返回True

? ? ? ? put_nowait(item)? 相當(dāng)于 toput(item,False)

? ? ? ? get_nowait()? ? ? ? ??相當(dāng)于 toget(False).

? ??????task_done()? ? ? ? ? 任務(wù)執(zhí)行完畢

3.隊列的主要作用

? ? ? ? a.程序解耦

? ? ? ? b.提高效率

七:生產(chǎn)者消費(fèi)者模型

? ? ? ? 為啥要使用生產(chǎn)者和消費(fèi)者模式?

????????在線程世界里,生產(chǎn)者就是生產(chǎn)數(shù)據(jù)的線程,消費(fèi)者就是消費(fèi)數(shù)據(jù)的線程。在多線程開發(fā)當(dāng)中,如果生產(chǎn)者處理速度很快,而消費(fèi)者處理速度很慢,那么生產(chǎn)者就必須等待消費(fèi)者處理完,才能繼續(xù)生產(chǎn)數(shù)據(jù)。同樣的道理,如果消費(fèi)者的處理能力大于生產(chǎn)者,那么消費(fèi)者就必須等待生產(chǎn)者。為了解決這個問題于是引入了生產(chǎn)者和消費(fèi)者模式。

????????什么是生產(chǎn)者消費(fèi)者模式?

????????生產(chǎn)者消費(fèi)者模式是通過一個容器來解決生產(chǎn)者和消費(fèi)者的強(qiáng)耦合問題。生產(chǎn)者和消費(fèi)者彼此之間不直接通訊,而通過阻塞隊列來進(jìn)行通訊,所以生產(chǎn)者生產(chǎn)完數(shù)據(jù)之后不用等待消費(fèi)者處理,直接扔給阻塞隊列,消費(fèi)者不找生產(chǎn)者要數(shù)據(jù),而是直接從阻塞隊列里取,阻塞隊列就相當(dāng)于一個緩沖區(qū),平衡了生產(chǎn)者和消費(fèi)者的處理能力。

八:協(xié)程

? ??????協(xié)程:又稱微線程,纖程。簡單來講:是一種用戶態(tài)的輕量級線程。

? ? ? ? ?協(xié)程擁有自己的寄存器上下文和棧。協(xié)程調(diào)度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復(fù)先前保存的寄存器上下文和棧?;谶@點(diǎn):協(xié)程能保留上一次調(diào)用時的狀態(tài)(即所有局部狀態(tài)的一個特定組合),每次過程重入時,就相當(dāng)于進(jìn)入上一次調(diào)用的狀態(tài),換種說法:進(jìn)入上一次離開時所處邏輯流的位置。

? ??????優(yōu)勢:

????????????????無需線程上下文切換的開銷

????????????????無需原子操作鎖定及同步的開銷

????????????????方便切換控制流,簡化編程模型

????????????????高并發(fā)+高擴(kuò)展性+低成本:一個CPU能支持上萬的協(xié)程。

?? ??????缺點(diǎn):

????????????????無法利用多核資源:

? ? ? ? ? ? ? ? 協(xié)程本質(zhì)是個單線程,不能同時將單個CPU的多個核用上,需要和進(jìn)程配合才能運(yùn)行在多CPU上.除非cpu密集型應(yīng)用日常所編寫的絕大部分應(yīng)用都沒有這個必要。? ? ? ??

????????????????進(jìn)行阻塞(Blocking)操作(如IO時)會阻塞掉整個程序

? ? ? ? ??協(xié)程必備條件:

? ? ? ? ? ? ? ? a.必須在只有一個單線程里實(shí)現(xiàn)并發(fā)

? ? ? ? ? ? ? ? b.修改共享數(shù)據(jù)不需要加鎖

? ? ? ? ? ? ? ? c.用戶程序里自己保存多個控制流的上下文棧

? ? ? ? ? ? ? ? d.一個協(xié)程遇到IO操作自動切換到其它協(xié)程

? ??????????Greenlet:

? ?????????????????greenlet是一個用C實(shí)現(xiàn)的協(xié)程模塊,可以使你在任意函數(shù)間隨意切換。

?? ????????????????問題:上面的Greenlet遇到IO操作不能自動切換。

?? ??????????Gevent:

? ?????????????Gevent 是一個第三方庫,可以輕松通過gevent實(shí)現(xiàn)并發(fā)同步或異步編程。在gevent中用到的主要模式是Greenlet, 是以C擴(kuò)展模塊形式接入Python的輕量級協(xié)程。 Greenlet全部運(yùn)行在主程序操作系統(tǒng)進(jìn)程的內(nèi)部,但它們被協(xié)作式地調(diào)度。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一文讀懂Python多線程 1、線程和進(jìn)程 計算機(jī)的核心是CPU,它承擔(dān)了所有的計算任務(wù)。它就像一座工廠,時刻在運(yùn)...
    星丶雲(yún)閱讀 1,596評論 0 4
  • 她就是他的影子 他想逃離 但是開始練習(xí)和自己的影子做朋友 眼淚打濕了逃離的初衷 才明白年少輕狂的自己 有新的注釋
    初瀾閱讀 241評論 0 0
  • 今日看到一句話:假如你膽敢不珍惜自己的注意力,你的注意力就會被無情的被收割,然后被高價賣出去 是的前幾天我就發(fā)了一...
    逄格亮閱讀 327評論 0 0
  • 不知等是我的意志力太差,還是我遵循中國人的隨大流素質(zhì),本來自己的注意力就很分散,還是那么愛占小便宜。 自己從邏輯思...
    A把時間當(dāng)做朋友閱讀 318評論 1 3
  • 今天周四,又是和好姐妹晚上相約的日子。每逢這天,我總是要和先生請假的。為了減輕自己不能陪先生一起做飯的愧疚感,...
    我們的日常閱讀 446評論 0 2

友情鏈接更多精彩內(nèi)容