同步異步與阻塞非阻塞的理解:
概念比較抽象,結(jié)合具體的例子比較容易理解,比如小明燒了一壺水準(zhǔn)備泡咖啡來喝:
1.同步阻塞:小明在燒水的時(shí)候木张,什么也不干众辨,就等著水開,水開了以后再去泡咖啡舷礼,這叫同步阻塞
2.同步非阻塞:小明仍然在用壺?zé)槌梗贿^此時(shí)他不在傻傻的等著水開,而是先去玩了把王者榮耀妻献,每當(dāng)自己死了蛛株,就過來看看水開了沒有,如果水開了就去泡咖啡育拨,這叫同步非阻塞谨履。
3.異步阻塞:其實(shí)異步就不存在阻塞了,一會(huì)在說明
4.異步非阻塞:小明仍然燒水煮咖啡熬丧,此時(shí)他不傻乎乎的等待結(jié)果笋粟,而是先去做別的事情,等他聽到了水壺的響聲以后析蝴,過來直接取燒開的水來泡咖啡害捕,這種叫異步非阻塞。
同步:是指程序發(fā)起一個(gè)請(qǐng)求之后嫌变,直到請(qǐng)求返回結(jié)果之后吨艇,才進(jìn)行下一步操作,簡單說就是一件事做完才能去做下一件事腾啥,比如我發(fā)起一個(gè)網(wǎng)絡(luò)請(qǐng)求查詢一個(gè)人的身份證东涡,然后根據(jù)身份證查看這個(gè)人的詳細(xì)信息。那么我查詢?cè)敿?xì)信息的操作需要等待查詢身份證的操作倘待,那么此時(shí)查詢身份證的操作就是一個(gè)同步操作疮跑。
異步:異步很明顯是與同步相對(duì),二者的區(qū)別在于是否需要等待某操作的返回結(jié)果凸舵。簡單來說祖娘,我們還是一個(gè)網(wǎng)絡(luò)請(qǐng)求,如果我們此時(shí)不需要依賴這個(gè)請(qǐng)求的結(jié)果就能進(jìn)行后續(xù)操作啊奄,那么此時(shí)這個(gè)網(wǎng)絡(luò)請(qǐng)求就是一個(gè)異步操作渐苏。
當(dāng)一個(gè)異步操作發(fā)出后,調(diào)用者在沒有得到結(jié)果之前菇夸,可以繼續(xù)執(zhí)行后續(xù)操作琼富。這就是異步。
阻塞:
阻塞的概念往往伴隨著線程庄新。阻塞一般是指:在調(diào)用結(jié)果返回之前鞠眉,當(dāng)前線程會(huì)被掛起薯鼠。調(diào)用線程只有在得到結(jié)果之后才會(huì)被喚醒執(zhí)行后續(xù)的操作。
非阻塞:
那么非阻塞械蹋,毫無疑問是阻塞的反向操作出皇。非阻塞式的調(diào)用指:在結(jié)果沒有返回之前,該調(diào)用不會(huì)阻塞住當(dāng)前線程哗戈。
感覺阻塞/非阻塞和同步/異步有異曲同工的地方郊艘?
其實(shí),這兩者存在本質(zhì)的區(qū)別唯咬,面向的對(duì)象是不同的暇仲。
阻塞/非阻塞:進(jìn)程/線程需要操作的數(shù)據(jù)如果尚未就緒,是否妨礙了當(dāng)前進(jìn)程/線程的后續(xù)操作副渴。
同步/異步:數(shù)據(jù)如果尚未就緒奈附,是否需要等待數(shù)據(jù)結(jié)果。
二煮剧、并發(fā)和并行
二者的區(qū)分其實(shí)就在于四個(gè)字:是否同時(shí)斥滤。
并發(fā):當(dāng)有多個(gè)線程在操作時(shí),如果系統(tǒng)只有一個(gè)CPU勉盅,操作系統(tǒng)只能把CPU運(yùn)行時(shí)間劃分成若干個(gè)時(shí)間段,再將時(shí)間段分配給各個(gè)線程執(zhí)行佑颇,在一個(gè)時(shí)間段的快速的切換不同的線程代碼運(yùn)行。
并行:當(dāng)系統(tǒng)有多個(gè)CPU時(shí)草娜,可以存在當(dāng)一個(gè)CPU執(zhí)行一個(gè)線程時(shí)挑胸,另一個(gè)CPU可以執(zhí)行另一個(gè)線程,兩個(gè)線程互不搶占CPU資源宰闰,可以同時(shí)進(jìn)行茬贵。
再舉個(gè)例子來形象的理解,
小明吃飯吃到一半移袍,電話來了解藻,小明一直到吃完了以后才去接。既不并發(fā)也不并行
小明吃飯吃到一半葡盗,電話來了螟左,小明停了下來接了電話,接完后繼續(xù)吃飯觅够。這是并發(fā)
小名吃飯吃到一半胶背,電話來了,小明一邊打電話一邊吃飯喘先。這是并行
三钳吟、python中的線程進(jìn)程和協(xié)程
先用一句話來總結(jié):一個(gè)程序就是一個(gè)進(jìn)程,進(jìn)程可以擁有多個(gè)線程苹祟,而協(xié)程是微線程砸抛。
1.進(jìn)程:進(jìn)程一般由程序、數(shù)據(jù)集树枫、進(jìn)程控制塊三部分組成直焙。我們編寫的程序用來描述進(jìn)程要完成哪些功能以及如何完成;數(shù)據(jù)集則是程序在執(zhí)行過程中所需要使用的資源砂轻;進(jìn)程控制塊用來記錄進(jìn)程的外部特征奔誓,描述進(jìn)程的執(zhí)行變化過程,系統(tǒng)可以利用它來控制和管理進(jìn)程搔涝,它是系統(tǒng)感知進(jìn)程存在的唯一標(biāo)志厨喂。比較抽象但容易理解,python的進(jìn)程通過multiprocessing.process()來創(chuàng)建庄呈。
Pool類描述了一個(gè)工作進(jìn)程池蜕煌,他有幾種不同的方法讓任務(wù)卸載工作進(jìn)程。進(jìn)程池內(nèi)部維護(hù)一個(gè)進(jìn)程序列诬留,當(dāng)使用時(shí)斜纪,則去進(jìn)程池中獲取一個(gè)進(jìn)程,如果進(jìn)程池序列中沒有可供使用的進(jìn)進(jìn)程文兑,那么程序就會(huì)等待盒刚,直到進(jìn)程池中有可用進(jìn)程為止。
我們可以用Pool類創(chuàng)建一個(gè)進(jìn)程池绿贞, 展開提交的任務(wù)給進(jìn)程池因块。
2.線程:線程是屬于進(jìn)程的,線程運(yùn)行在進(jìn)程空間內(nèi)籍铁,同一進(jìn)程所產(chǎn)生的線程共享同一內(nèi)存空間涡上,當(dāng)進(jìn)程退出時(shí)該進(jìn)程所產(chǎn)生的線程都會(huì)被強(qiáng)制退出并清除。線程可與屬于同一進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源拒名,線程是應(yīng)用程序工作的最小單元吓懈。python的線程是通過threading.Thread()來創(chuàng)建的。
GIL:(global interpreter lock)全局解釋器鎖:這是CPython所獨(dú)有的靡狞,而且我們用的也大多數(shù)是CPython耻警,所以在Cpython中,多線程其實(shí)是偽多線程甸怕,只是因?yàn)榫€程切換速度很快一般發(fā)覺不到而已甘穿,但他確實(shí)存在,所以在實(shí)際中能用多進(jìn)程盡量不要用多線程梢杭。
3.協(xié)程:
線程和進(jìn)程的操作是由程序觸發(fā)系統(tǒng)接口温兼,最后的執(zhí)行者是系統(tǒng);協(xié)程的操作則是程序員武契。
協(xié)程存在的意義:對(duì)于多線程應(yīng)用募判,CPU通過切片的方式來切換線程間的執(zhí)行荡含,線程切換時(shí)需要耗時(shí)(保存狀態(tài),下次繼續(xù))届垫。協(xié)程释液,則只使用一個(gè)線程,在一個(gè)線程中規(guī)定某個(gè)代碼塊執(zhí)行順序装处。
協(xié)程的適用場景:當(dāng)程序中存在大量不需要CPU的操作時(shí)(IO)误债,適用于協(xié)程;
event loop是協(xié)程執(zhí)行的控制點(diǎn)妄迁, 如果你希望執(zhí)行協(xié)程寝蹈, 就需要用到它們。
子程序(函數(shù))在執(zhí)行過程中可以中斷去執(zhí)行別的子程序登淘;別的子程序也可以中斷回來繼續(xù)執(zhí)行之前的子程序箫老,那么很容易想到Python的yield,顯然yield是可以實(shí)現(xiàn)這種切換的黔州。python用到協(xié)程的標(biāo)志之一就是yield槽惫。
協(xié)程的優(yōu)點(diǎn):
(1)無需線程上下文切換的開銷辩撑,協(xié)程避免了無意義的調(diào)度界斜,由此可以提高性能(但也因此,程序員必須自己承擔(dān)調(diào)度的責(zé)任合冀,同時(shí)各薇,協(xié)程也失去了標(biāo)準(zhǔn)線程使用多CPU的能力)
(2)無需原子操作鎖定及同步的開銷
【伞(3)方便切換控制流峭判,簡化編程模型
(4)高并發(fā)+高擴(kuò)展性+低成本:一個(gè)CPU支持上萬的協(xié)程都不是問題棕叫。所以很適合用于高并發(fā)處理林螃。
協(xié)程的缺點(diǎn):
(1)無法利用多核資源:協(xié)程的本質(zhì)是個(gè)單線程,它不能同時(shí)將 單個(gè)CPU 的多個(gè)核用上,協(xié)程需要和進(jìn)程配合才能運(yùn)行在多CPU上.當(dāng)然我們?nèi)粘K帉懙慕^大部分應(yīng)用都沒有這個(gè)必要俺泣,除非是cpu密集型應(yīng)用疗认。
(2)進(jìn)行阻塞(Blocking)操作(如IO時(shí))會(huì)阻塞掉整個(gè)程序