1.1異步相關(guān)概念:初步了解-創(chuàng)新互聯(lián)

1.進(jìn)程和線程的概念

計(jì)算機(jī)有5大基本組成部分,運(yùn)算器,控制器,存儲(chǔ)器,輸入和輸出。運(yùn)算器和控制器封裝到一起,加上寄存器組和cpu內(nèi)部總線構(gòu)成中央處理器(CPU)。cpu的根本任務(wù),就是執(zhí)行指令,對(duì)計(jì)算機(jī)來說,都是0,1組成的序列,cpu從邏輯上可以劃分為3個(gè)模塊:控制單元、運(yùn)算單元和存儲(chǔ)單元。這三個(gè)部分由cpu總線連接起來。

創(chuàng)新互聯(lián)公司專注于網(wǎng)站建設(shè)|成都網(wǎng)站維護(hù)|優(yōu)化|托管以及網(wǎng)絡(luò)推廣,積累了大量的網(wǎng)站設(shè)計(jì)與制作經(jīng)驗(yàn),為許多企業(yè)提供了網(wǎng)站定制設(shè)計(jì)服務(wù),案例作品覆蓋成都混凝土攪拌站等行業(yè)。能根據(jù)企業(yè)所處的行業(yè)與銷售的產(chǎn)品,結(jié)合品牌形象的塑造,量身制作品質(zhì)網(wǎng)站。

在這里插入圖片描述
CPU的運(yùn)行原理就是:控制單元在時(shí)序脈沖的作用下,將指令計(jì)數(shù)器里所指向的指令地址(這個(gè)地址是在內(nèi)存里的)送到地址總線上去,然后CPU將這個(gè)地址里的指令讀到指令寄存器進(jìn)行譯碼。對(duì)于執(zhí)行指令過程中所需要用到的數(shù)據(jù),會(huì)將數(shù)據(jù)地址也送到地址總線,然后CPU把數(shù)據(jù)讀到CPU的內(nèi)部存儲(chǔ)單元(就是內(nèi)部寄存器)暫存起來,最后命令運(yùn)算單元對(duì)數(shù)據(jù)進(jìn)行處理加工。周而復(fù)始,一直這樣執(zhí)行下去。

2.并發(fā)和并行

并發(fā):并發(fā)當(dāng)有多個(gè)線程在操作時(shí),如果系統(tǒng)只有一個(gè)CPU,則它根本不可能真正同時(shí)進(jìn)行一個(gè)以上的線程,它只能把CPU運(yùn)行時(shí)間劃分成若干個(gè)時(shí)間段,再將時(shí)間 段分配給各個(gè)線程執(zhí)行,在一個(gè)時(shí)間段的線程代碼運(yùn)行時(shí),其它線程處于掛起狀。.這種方式我們稱之為并發(fā)(Concurrent)。

并行:當(dāng)系統(tǒng)有一個(gè)以上CPU時(shí),則線程的操作有可能非并發(fā)。當(dāng)一個(gè)CPU執(zhí)行一個(gè)線程時(shí),另一個(gè)CPU可以執(zhí)行另一個(gè)線程,兩個(gè)線程互不搶占CPU資源,可以同時(shí)進(jìn)行,這種方式我們稱之為并行(Parallel)。

并發(fā)與并行的區(qū)別:

  • 并發(fā)不是同時(shí)發(fā)生,并行是同時(shí)發(fā)生。 并發(fā)是邏輯上的同時(shí)發(fā)生(simultaneous),而并行是物理上的同時(shí)發(fā)生。
  • 并發(fā)是指一個(gè)處理器同時(shí)處理多個(gè)任務(wù)。并行是指多個(gè)處理器或者是多核的處理器同時(shí)處理多個(gè)不同的任務(wù)。
  • 并發(fā)是在同一個(gè)cpu上同時(shí)(不是真正的同時(shí),而是看來是同時(shí),因?yàn)镃PU要在多個(gè)程序之間切換)運(yùn)行多個(gè)程序。
  • 并行是每一個(gè)CPU運(yùn)行一個(gè)程序。
3.多核、多CPU、CPU與多線程、多進(jìn)程的關(guān)系
  • 進(jìn)程是資源分配的最小單位,一個(gè)程序有至少一個(gè)進(jìn)程。線程是程序執(zhí)行的最小單位。一個(gè)進(jìn)程有至少一個(gè)線程。
  • 進(jìn)程有自己的獨(dú)立地址空間,每啟動(dòng)一個(gè)進(jìn)程,系統(tǒng)就會(huì)為它分配地址空間,建立數(shù)據(jù)表來維護(hù)代碼段、堆棧段和數(shù)據(jù)段,這種操作非常昂貴。而線程是共享進(jìn)程中的數(shù)據(jù)的,使用相同的地址空間,因此CPU切換一個(gè)線程的花費(fèi)遠(yuǎn)比進(jìn)程要小很多,同時(shí)創(chuàng)建一個(gè)線程的開銷也比進(jìn)程要小很多。
  • 線程之間的通信更方便,同一進(jìn)程下的線程共享全局變量、靜態(tài)變量等數(shù)據(jù),而進(jìn)程之間的通信需要以通信的方式(IPC)進(jìn)行。不過如何處理好同步與互斥是編寫多線程程序的難點(diǎn)。
  • 多cpu的運(yùn)行,對(duì)應(yīng)進(jìn)程的運(yùn)行狀態(tài);多核cpu的運(yùn)行,對(duì)應(yīng)線程的運(yùn)行狀態(tài)。
  • 單CPU中進(jìn)程只能是并發(fā),多CPU計(jì)算機(jī)中進(jìn)程可以并行。
  • 單CPU單核中線程只能并發(fā),單CPU多核中線程可以并行。
  • 一個(gè)進(jìn)程中可以有多條執(zhí)行路徑同時(shí)執(zhí)行,一個(gè)線程就是進(jìn)程中的一條執(zhí)行路徑。
4.多進(jìn)程(multi-processing) 和多線程(multi-threading)的區(qū)別

多進(jìn)程是各個(gè)并行任務(wù)之間“不使用“共同的內(nèi)存空間;而多線程的各個(gè)并行任務(wù)”使用“共同的內(nèi)存空間。

(1)多進(jìn)程
  • 優(yōu)點(diǎn):獨(dú)立內(nèi)存空間;實(shí)現(xiàn)代碼直觀簡(jiǎn)單;充分利用多核多CPU;避免全局解釋器鎖的限制;
  • 缺點(diǎn):無法實(shí)現(xiàn)對(duì)象和內(nèi)容共享;需要較大的內(nèi)存空間。
  • 應(yīng)用:一般用于數(shù)學(xué)計(jì)算、數(shù)據(jù)處理等場(chǎng)景,計(jì)算密集型(CPU密集型)任務(wù)指的是需要做大量的邏輯運(yùn)算。
(2) 多線程
  • 優(yōu)點(diǎn):輕量,需要的額外內(nèi)存較??;共享內(nèi)存,方便訪問;對(duì)于CPython解釋器,可以通過全局解釋器鎖使用C擴(kuò)展;適合I/O密集型任務(wù)。
  • 缺點(diǎn):全局解釋器鎖的限制;并行任務(wù)不能殺掉;實(shí)現(xiàn)代碼較為復(fù)雜。
  • 一般用于爬蟲請(qǐng)求、文件讀寫等場(chǎng)景。IO密集型任務(wù)指的是輸入輸出型。
(3)實(shí)現(xiàn)方式
  • 實(shí)現(xiàn)多線程的方式:threading.Thread()、線程池concurrent.futures.ThreadPoolExecutor
  • 實(shí)現(xiàn)多進(jìn)程的方式:multiprocessing.Process、進(jìn)程池concurrent.futures.ProcessPoolExecutor
(4)多線程與多進(jìn)程的應(yīng)用場(chǎng)景不一樣:
  • 線程的創(chuàng)建開銷小、由于GIL的存在,無法真正并行,適合GUI、網(wǎng)絡(luò)通信、文件讀寫等IO密集型場(chǎng)景;
  • 進(jìn)程的創(chuàng)建開銷大,可以充分利用多個(gè)CPU實(shí)現(xiàn)并行,適合計(jì)算量比較大(比如單個(gè)函數(shù)執(zhí)行需要幾分鐘、幾十分鐘以上),且無需IO(簡(jiǎn)單地說就是數(shù)據(jù)已經(jīng)在內(nèi)存中,不需要讀取磁盤、不需要網(wǎng)絡(luò)通信)的場(chǎng)景。
  • 多線程、多進(jìn)程都不適合的場(chǎng)景:基本不涉及IO或只讀取一次文件這種,且計(jì)算量不大,單線程短時(shí)間就能結(jié)束(一兩秒左右)的情況下,單進(jìn)程單線程是最好的。
5.python的全局解釋器鎖GIL

Python 全局解釋器鎖或GIL,簡(jiǎn)單來說,是一個(gè)互斥鎖(或鎖),它只允許一個(gè)線程控制 Python 解釋器。這意味著在任何時(shí)間點(diǎn)都只能有一個(gè)線程處于執(zhí)行狀態(tài)。執(zhí)行單線程程序的開發(fā)人員看不到 GIL 的影響,但它可能是 CPU 密集型和多線程代碼中的性能瓶頸。由于即使在具有多個(gè) CPU 內(nèi)核的多線程架構(gòu)中,GIL 也只允許一次執(zhí)行一個(gè)線程,因此 GIL 被稱為 Python 的“臭名昭著”的特性,但是它確實(shí)為Python內(nèi)存處理提供了方便。

如果一個(gè)對(duì)象同時(shí)被多個(gè)線程來引用,那么引用計(jì)數(shù)可能同時(shí)增加或減少,每個(gè)線程按照自己的方式進(jìn)行計(jì)數(shù),對(duì)象在整個(gè)內(nèi)存中的引用變得十分混亂,很容易造成內(nèi)存泄漏或者其他很多不可預(yù)見的Bug。一個(gè)解決辦法給就是每個(gè)線程都給引用計(jì)數(shù)加一個(gè)鎖,阻止別人修改,不過這樣會(huì)造成鎖死現(xiàn)象(比如一個(gè)對(duì)象有多個(gè)鎖時(shí)),另外,大量的資源會(huì)浪費(fèi)在加鎖解鎖的過程了,嚴(yán)重拖慢了程序運(yùn)行速度。

這個(gè)時(shí)候,就需要一個(gè)統(tǒng)一來管理引用計(jì)數(shù)的機(jī)制,以確保對(duì)象引用計(jì)數(shù)準(zhǔn)確、安全。全局解釋器鎖就是用來處理這種情況的。它既避免了不同線程帶來的引用計(jì)數(shù)混亂,又避免了過多線程鎖帶來的死鎖和運(yùn)行效率低的問題。雖然全局解釋器鎖解決了對(duì)象引用計(jì)數(shù)的問題,但隨之而來的是,很多CPU密集型任務(wù)在全局解釋器鎖的作用下,實(shí)際上變成了單線程,不能充分發(fā)揮CPU的算力,影響程序速度。

全局解釋器鎖并不是Python獨(dú)有的,其他一些語言,比如Ruby也存在全局解釋器鎖。還有一些語言沒有使用引用計(jì)數(shù)的方式來管理內(nèi)容,而是使用垃圾回收機(jī)制(GC)來管理內(nèi)存。雖然這樣避免了全局解釋器鎖,但是在單線程處理上,GC并不占有優(yōu)勢(shì)。

全局解釋器鎖對(duì)多線程的影響

  • 首先應(yīng)該區(qū)分不同性質(zhì)的任務(wù),有一些是CPU密集型的任務(wù),有一些是I/O密集型的任務(wù)。
    CPU密集型的任務(wù)在大程度上使用了CPU,比如數(shù)學(xué)矩陣的計(jì)算、圖像處理、文件解壓縮等?!疽话闶褂枚噙M(jìn)程應(yīng)對(duì)】
  • I/O密集型任務(wù)在需要花費(fèi)很多時(shí)間來等待信息的輸入和輸出(讀寫),比如從網(wǎng)址下載內(nèi)容,大量訪問磁盤進(jìn)行讀寫等。【一般使用多線程應(yīng)對(duì)】
6.進(jìn)程池

進(jìn)程就是運(yùn)行著的程序。寫的python程序(或者其他應(yīng)用程序比如畫筆、qq等),運(yùn)行起來,就稱之為一個(gè)進(jìn)程;在windows下面打開任務(wù)管理器,里面顯示了當(dāng)前系統(tǒng)上運(yùn)行著的進(jìn)程。這些程序還沒有運(yùn)行的時(shí)候,它們的程序代碼文件存儲(chǔ)在磁盤中,就是那些擴(kuò)展名為 .exe 文件。雙擊它們,這些 .exe 文件就被os加載到內(nèi)存中,運(yùn)行起來,成為進(jìn)程。

進(jìn)程池:可以提供指定數(shù)量的進(jìn)程給用戶使用,即當(dāng)有新的請(qǐng)求提交到進(jìn)程池中時(shí),如果池未滿,則會(huì)創(chuàng)建一個(gè)新的進(jìn)程用來執(zhí)行該請(qǐng)求;反之,如果池中的進(jìn)程數(shù)已經(jīng)達(dá)到規(guī)定大值,那么該請(qǐng)求就會(huì)等待,只要池中有進(jìn)程空閑下來,該請(qǐng)求就能得到執(zhí)行。

7.線程池

系統(tǒng)中每個(gè)進(jìn)程里面至少包含一個(gè) 線程 。線程是操作系統(tǒng)創(chuàng)建的,每個(gè)線程對(duì)應(yīng)一個(gè)代碼執(zhí)行的數(shù)據(jù)結(jié)構(gòu),保存了代碼執(zhí)行過程中的重要的狀態(tài)信息。沒有線程,操作系統(tǒng)沒法管理和維護(hù) 代碼運(yùn)行的狀態(tài)信息。所以沒有創(chuàng)建線程之前,操作系統(tǒng)是不會(huì)執(zhí)行我們的代碼的。

8.同步和異步
  • 同步,就是調(diào)用某個(gè)東西時(shí),調(diào)用方得等待這個(gè)調(diào)用返回結(jié)果才能繼續(xù)往后執(zhí)行。
  • 異步,和同步相反調(diào)用方不會(huì)等待得到結(jié)果,而是在調(diào)用發(fā)出后調(diào)用者可用繼續(xù)執(zhí)行后續(xù)操作,被調(diào)用者通過狀體來通知調(diào)用者,或者通過回掉函數(shù)來處理這個(gè)調(diào)用
9.隊(duì)列(線程間通信)

在一個(gè)進(jìn)程中,不同子線程負(fù)責(zé)不同的任務(wù),t1子線程負(fù)責(zé)獲取到數(shù)據(jù),t2子線程負(fù)責(zé)把數(shù)據(jù)保存的本地,那么他們之間的通信使用Queue來完成。因?yàn)樵僖粋€(gè)進(jìn)程中,數(shù)據(jù)變量是共享的,即多個(gè)子線程可以對(duì)同一個(gè)全局變量進(jìn)行操作修改,Queue是加了鎖的安全消息隊(duì)列。

Python的Queue隊(duì)列,主要用于多生產(chǎn)者和消費(fèi)者模式下的隊(duì)列實(shí)現(xiàn),特別適合多線程時(shí)的消息交換。通過使用隊(duì)列,把生產(chǎn)者和消費(fèi)者分解開來,作為其中的中間件,比如生產(chǎn)者產(chǎn)生一個(gè)數(shù)據(jù),然后放到queue隊(duì)列中,queue隊(duì)列在把這個(gè)數(shù)據(jù)放到消費(fèi)者線程中。使用單線程不必用隊(duì)列,但是隊(duì)列對(duì)于多線程來說是不可或缺的。

10.線程同步

如果沒有控制多個(gè)線程對(duì)同一資源的訪問,對(duì)數(shù)據(jù)造成破壞,使得線程運(yùn)行的結(jié)果不可預(yù)期。這種現(xiàn)象稱為“線程不安全”。同步就是協(xié)同步調(diào),按預(yù)定的先后次序進(jìn)行運(yùn)行。

"同"字從字面上容易理解為一起動(dòng)作,其實(shí)不是,"同"字應(yīng)是指協(xié)同、協(xié)助、互相配合。如進(jìn)程、線程同步,可理解為進(jìn)程或線程A和B一塊配合,A執(zhí)行到一定程度時(shí)要依靠B的某個(gè)結(jié)果,于是停下來,示意B運(yùn)行;B依言執(zhí)行,再將結(jié)果給A;A再繼續(xù)操作。

實(shí)現(xiàn)線程同步的方式可以是:

  • 線程鎖
  • 條件變量
  • 信號(hào)變量
  • 事件
11.生產(chǎn)者與消費(fèi)者

生產(chǎn)者消費(fèi)者模型具體來講,就是在一個(gè)系統(tǒng)中,存在生產(chǎn)者和消費(fèi)者兩種角色,他們通過內(nèi)存緩沖區(qū)進(jìn)行通信,生產(chǎn)者生產(chǎn)消費(fèi)者需要的資料,消費(fèi)者消耗數(shù)據(jù)或者資料。

舉一個(gè)寄信的例子,假設(shè)要寄一封信,大致過程如下:

  1. 你把信寫好-―相當(dāng)于生產(chǎn)者制造數(shù)據(jù);
  2. 把信放入郵簡(jiǎn)――相當(dāng)于生產(chǎn)者把數(shù)據(jù)放入緩沖區(qū);
  3. 遞員把信從郵簡(jiǎn)取出—一相當(dāng)于消費(fèi)者把數(shù)據(jù)取出緩沖區(qū);
  4. 遞員把信拿去郵局做相應(yīng)的處理――相當(dāng)于消費(fèi)者處理數(shù)據(jù);
12.daemon和non-daemon線程

Python 中,構(gòu)造線程的時(shí)候,可以設(shè)置daemon屬性,這個(gè)屬性必須再start()方法前設(shè)置好。線程daemon屬性,如果設(shè)定就是用戶的設(shè)置,否則就取當(dāng)前線程的daemon值。主線程是non-daemon線程,即daemon = False。線程具有一個(gè)daemon屬性,可以手動(dòng)設(shè)置為True或者False,也可以不設(shè)置,則取默認(rèn)值為None。

如果除主線程之外還有non-daemon線程的時(shí)候,主線程退出時(shí),也不會(huì)殺掉所有daemon線程,直到所有non-daemon線程全部結(jié)束,如果還有daemon線程,主線程需要退出,會(huì)結(jié)束所有daemon線程,程序退出。

13.鎖和共享內(nèi)存

【多線程、多進(jìn)程涉及讀寫必須要用鎖,一定要用】

(1)多線程的線程鎖

①死鎖問題和解決
如果多個(gè)線程要調(diào)用多個(gè)現(xiàn)象,而A線程調(diào)用A鎖占用了A對(duì)象,B線程調(diào)用了B鎖占用了B對(duì)象,A線程不能調(diào)用B對(duì)象,B線程不能調(diào)用A對(duì)象,于是一直等待。這就造成了線程“死鎖”。Threading模塊中,也有一個(gè)類,RLock,稱之為可重入鎖。該鎖對(duì)象內(nèi)部維護(hù)著一個(gè)Lock和一個(gè)counter對(duì)象。counter對(duì)象記錄了acquire的次數(shù),使得資源可以被多次require。最后,當(dāng)所有RLock被release后,其他線程才能獲取資源。在同一個(gè)線程中,RLock.acquire可以被多次調(diào)用,利用該特性,可以解決部分死鎖問題

②當(dāng)多個(gè)線程同時(shí)訪問一個(gè)數(shù)據(jù)時(shí),需加鎖,排隊(duì)變成單線程一個(gè)一個(gè)執(zhí)行,避免出錯(cuò)。
③加鎖避免并發(fā)導(dǎo)致邏輯出錯(cuò)。

④每當(dāng)一個(gè)線程a要訪問共享數(shù)據(jù)時(shí),必須先獲得鎖定;如果已經(jīng)有別的線程b獲得鎖定了,那么就讓線程a暫停,也就是同步阻塞;等到線程b訪問完畢,釋放鎖以后,再讓線程a繼續(xù)。

⑤同一時(shí)刻只允許一個(gè)線程操作該數(shù)據(jù),可以保證數(shù)據(jù)安全。 線程鎖用于鎖定資源,可以同時(shí)使用多個(gè)鎖,當(dāng)需要獨(dú)占某一資源時(shí),任何一個(gè)鎖都可以鎖這個(gè)資源。

⑥將一段代碼鎖住,一旦獲得鎖權(quán)限,除非釋放線程鎖,否則其他代碼都無法獲得鎖權(quán)限。

(2)多進(jìn)程的進(jìn)程鎖

①很多時(shí)候,需要在多個(gè)進(jìn)程中同時(shí)寫一個(gè)文件,如果不加鎖機(jī)制,就會(huì)導(dǎo)致寫文件錯(cuò)亂。
②誰先搶到鎖誰先執(zhí)行,等到該進(jìn)程執(zhí)行完成后,其它進(jìn)程再搶鎖執(zhí)行。
③python多進(jìn)程編程使用進(jìn)程池非常的方便管理進(jìn)程,但是有時(shí)候子進(jìn)程之間會(huì)搶占一些獨(dú)占資源,比如consol或者比如日志文件的寫入權(quán)限,這樣的時(shí)候我們一般需要共享一個(gè)Lock來對(duì)獨(dú)占資源加鎖。

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

網(wǎng)站題目:1.1異步相關(guān)概念:初步了解-創(chuàng)新互聯(lián)
轉(zhuǎn)載來源:http://muchs.cn/article38/eehsp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、搜索引擎優(yōu)化定制開發(fā)、網(wǎng)站設(shè)計(jì)、靜態(tài)網(wǎng)站、服務(wù)器托管

廣告

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

外貿(mào)網(wǎng)站制作