同步異步與阻塞非阻塞的理解:
概念比較抽象,結合具體的例子比較容易理解,比如小明燒了一壺水準備泡咖啡來喝:
1.同步阻塞:小明在燒水的時候,什么也不干,就等著水開,水開了以后再去泡咖啡,這叫同步阻塞
2.同步非阻塞:小明仍然在用壺燒水,不過此時他不在傻傻的等著水開,而是先去玩了把王者榮耀,每當自己死了,就過來看看水開了沒有,如果水開了就去泡咖啡,這叫同步非阻塞。
3.異步阻塞:其實異步就不存在阻塞了,一會在說明
4.異步非阻塞:小明仍然燒水煮咖啡,此時他不傻乎乎的等待結果,而是先去做別的事情,等他聽到了水壺的響聲以后,過來直接取燒開的水來泡咖啡,這種叫異步非阻塞。
同步:是指程序發起一個請求之后,直到請求返回結果之后,才進行下一步操作,簡單說就是一件事做完才能去做下一件事,比如我發起一個網絡請求查詢一個人的身份證,然后根據身份證查看這個人的詳細信息。那么我查詢詳細信息的操作需要等待查詢身份證的操作,那么此時查詢身份證的操作就是一個同步操作。
異步:異步很明顯是與同步相對,二者的區別在于是否需要等待某操作的返回結果。簡單來說,我們還是一個網絡請求,如果我們此時不需要依賴這個請求的結果就能進行后續操作,那么此時這個網絡請求就是一個異步操作。
當一個異步操作發出后,調用者在沒有得到結果之前,可以繼續執行后續操作。這就是異步。
阻塞:
阻塞的概念往往伴隨著線程。阻塞一般是指:在調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之后才會被喚醒執行后續的操作。
非阻塞:
那么非阻塞,毫無疑問是阻塞的反向操作。非阻塞式的調用指:在結果沒有返回之前,該調用不會阻塞住當前線程。
感覺阻塞/非阻塞和同步/異步有異曲同工的地方?
其實,這兩者存在本質的區別,面向的對象是不同的。
阻塞/非阻塞:進程/線程需要操作的數據如果尚未就緒,是否妨礙了當前進程/線程的后續操作。
同步/異步:數據如果尚未就緒,是否需要等待數據結果。
二、并發和并行
二者的區分其實就在于四個字:是否同時。
并發:當有多個線程在操作時,如果系統只有一個CPU,操作系統只能把CPU運行時間劃分成若干個時間段,再將時間段分配給各個線程執行,在一個時間段的快速的切換不同的線程代碼運行。
并行:當系統有多個CPU時,可以存在當一個CPU執行一個線程時,另一個CPU可以執行另一個線程,兩個線程互不搶占CPU資源,可以同時進行。
再舉個例子來形象的理解,
小明吃飯吃到一半,電話來了,小明一直到吃完了以后才去接。既不并發也不并行
小明吃飯吃到一半,電話來了,小明停了下來接了電話,接完后繼續吃飯。這是并發
小名吃飯吃到一半,電話來了,小明一邊打電話一邊吃飯。這是并行
三、python中的線程進程和協程
先用一句話來總結:一個程序就是一個進程,進程可以擁有多個線程,而協程是微線程。
1.進程:進程一般由程序、數據集、進程控制塊三部分組成。我們編寫的程序用來描述進程要完成哪些功能以及如何完成;數據集則是程序在執行過程中所需要使用的資源;進程控制塊用來記錄進程的外部特征,描述進程的執行變化過程,系統可以利用它來控制和管理進程,它是系統感知進程存在的唯一標志。比較抽象但容易理解,python的進程通過multiprocessing.process()來創建。
Pool類描述了一個工作進程池,他有幾種不同的方法讓任務卸載工作進程。進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程,如果進程池序列中沒有可供使用的進進程,那么程序就會等待,直到進程池中有可用進程為止。
我們可以用Pool類創建一個進程池, 展開提交的任務給進程池。
2.線程:線程是屬于進程的,線程運行在進程空間內,同一進程所產生的線程共享同一內存空間,當進程退出時該進程所產生的線程都會被強制退出并清除。線程可與屬于同一進程的其它線程共享進程所擁有的全部資源,線程是應用程序工作的最小單元。python的線程是通過threading.Thread()來創建的。
GIL:(global interpreter lock)全局解釋器鎖:這是CPython所獨有的,而且我們用的也大多數是CPython,所以在Cpython中,多線程其實是偽多線程,只是因為線程切換速度很快一般發覺不到而已,但他確實存在,所以在實際中能用多進程盡量不要用多線程。
3.協程:
線程和進程的操作是由程序觸發系統接口,最后的執行者是系統;協程的操作則是程序員。
協程存在的意義:對于多線程應用,CPU通過切片的方式來切換線程間的執行,線程切換時需要耗時(保存狀態,下次繼續)。協程,則只使用一個線程,在一個線程中規定某個代碼塊執行順序。
協程的適用場景:當程序中存在大量不需要CPU的操作時(IO),適用于協程;
event loop是協程執行的控制點, 如果你希望執行協程, 就需要用到它們。
子程序(函數)在執行過程中可以中斷去執行別的子程序;別的子程序也可以中斷回來繼續執行之前的子程序,那么很容易想到Python的yield,顯然yield是可以實現這種切換的。python用到協程的標志之一就是yield。
協程的優點:
(1)無需線程上下文切換的開銷,協程避免了無意義的調度,由此可以提高性能(但也因此,程序員必須自己承擔調度的責任,同時,協程也失去了標準線程使用多CPU的能力)
(2)無需原子操作鎖定及同步的開銷
(3)方便切換控制流,簡化編程模型
(4)高并發+高擴展性+低成本:一個CPU支持上萬的協程都不是問題。所以很適合用于高并發處理。
協程的缺點:
(1)無法利用多核資源:協程的本質是個單線程,它不能同時將 單個CPU 的多個核用上,協程需要和進程配合才能運行在多CPU上.當然我們日常所編寫的絕大部分應用都沒有這個必要,除非是cpu密集型應用。
(2)進行阻塞(Blocking)操作(如IO時)會阻塞掉整個程序