阻塞和非阻塞,同步和非同步 總結

2022-06-14 22:06:11 字數 3395 閱讀 3264

故事:老王燒開水。

出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。

老王想了想,有好幾種等待方式

1.老王用水壺煮水,並且站在那裡,不管水開沒開,每隔一定時間看看水開了沒。-同步阻塞

老王想了想,這種方法不夠聰明。

2.老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網,但是還是會每隔一段時間過來看看水開了沒有,水沒有開就走人。-同步非阻塞

老王想了想,現在的方法聰明了些,但是還是不夠好。

3.老王這次使用高大上的響水壺來煮水,站在那裡,但是不會再每隔一段時間去看水開,而是等水開了,水壺會自動的通知他。-非同步阻塞

老王想了想,不會呀,既然水壺可以通知我,那我為什麼還要傻傻的站在那裡等呢,嗯,得換個方法。

4.老王還是使用響水壺煮水,跑到客廳上網去,等著響水壺自己把水煮熟了以後通知他。-非同步非阻塞

老王豁然,這下感覺輕鬆了很多。

其實,這兩者存在本質的區別,它們的修飾物件是不同的。阻塞和非阻塞是指程序訪問的資料如果尚未就緒,程序是否需要等待,簡單說這相當於函式內部的實現區別,也就是未就緒時是直接返回還是等待就緒。

而同步和非同步是指訪問資料的機制,同步一般指主動請求並等待i/o操作完畢的方式,當資料就緒後在讀寫的時候必須阻塞,非同步則指主動請求資料後便可以繼續處理其它任務,隨後等待i/o,操作完畢的通知,這可以使程序在資料讀寫時也不阻塞。

網路io的模型大致包括下面幾種

非同步io(asynchronous io)

網路io的本質是socket的讀取,socket在linux系統被抽象為流,io可以理解為對流的操作。對於一次io訪問,資料會先被拷貝到作業系統核心的緩衝區中,然後才會從作業系統核心的緩衝區拷貝到應用程式的位址空間,所以一般會經歷兩個階段:

等待所有資料都準備好或者一直在等待資料,有資料的時候將資料拷貝到系統核心;

將核心快取中資料拷貝到使用者程序中;

對於socket流而言:

等待網路上的資料分組到達,然後被複製到核心的某個緩衝區;

把資料從核心緩衝區複製到應用程序緩衝區中;

2.1.1 介紹

這也是最常用的模型,預設情況下所有的套接字都是阻塞的;

我們把recvfrom函式視為系統呼叫,因為我們正區分程序和核心,系統呼叫一般都會從在應用程序空間中執行切換到核心空間中執行,一段時間後又再切換回來;

我們可以從圖中看到,應用程序從進行系統呼叫複製資料報到應用程序的緩衝區完成的整段時間內是被阻塞的;在這個過程中,要麼正確到達,要麼系統呼叫被訊號打斷;直到資料報被複製到使用者程序完成後,使用者程序才解除阻塞的狀態,當然,這是使用者程序自己進行的阻塞;

2.1.2 優點和缺點2.2.1 介紹

非阻塞,當所請求的i/o操作非得把當前程序設定成睡眠才能完成時,不要把當前程序設定成睡眠,而是返回乙個錯誤資訊(資料報沒有準備好的情況下),此時當前程序可以做其它的事情,不用阻塞;

從圖中可以得知,前三次系統呼叫時都沒有資料可以返回,核心均返回乙個ewouldblock,並且不會阻塞當前程序,直到第四次詢問核心緩衝區是否有資料的時候,此時核心緩衝區中已經有乙個準備好的資料,因此將核心資料複製到使用者空間,此時系統呼叫則返回成功;

當乙個應用程序像這樣對乙個非阻塞socket迴圈呼叫recv/recvfrom時,則稱為輪詢;應用程序持續輪詢核心,以檢視某個操作是否就緒,這麼做往往消耗大量的cpu時間。

2.2.2 優點和缺點2.3.1 介紹

有了i/o復用,我們就可以呼叫select或poll,讓其阻塞在兩個系統呼叫(1.詢問資料是否準備好並且直到資料準備好才返回;2.核心是否把資料全部複製完成到使用者程序)中的某乙個之上

圖中阻塞於select呼叫,等待資料報套接字變為可讀。當select返回套接字可讀這一條件的時候,則呼叫recvfrom把所讀資料報複製到應用程序緩衝區;

之前的同步非阻塞方式需要使用者程序不停的輪詢,但是io多路復用不需要不停的輪詢,而是派別人去幫忙迴圈查詢多個任務的完成狀態,unix/linux 下的select、poll、epoll就是幹這個的;select呼叫是核心級別的,select輪詢相對非阻塞的輪詢的區別在於---前者可以等待多個socket,能實現同時對多個io埠進行監聽,當其中任何乙個socket的資料準好了,就能返回進行可讀,然後程序再進行recvform系統呼叫,將資料由核心拷貝到使用者程序,當然這個過程是阻塞的。select或poll呼叫之後,會阻塞程序,與blocking io阻塞不同在於,此時的select不是等到socket資料全部到達再處理, 而是有了一部分資料(網路上的資料是分組到達的)就會呼叫使用者程序來處理。如何知道有一部分資料到達了呢?監視的事情交給了核心,核心負責資料到達的處理。

我認為上面那句話中存在兩個重要點:1.對多個socket進行監聽,只要任何乙個socket資料準備好就返回可讀;2.不等乙個socket資料全部到達再處理,而是一部分socket的資料到達了就通知使用者程序;

其實select、poll、epoll的原理就是不斷的遍歷所負責的所有的socket完成狀態,當某個socket有資料到達了,就返回可讀並通知使用者程序來處理;

2.3.2 優點和缺點

2.3.3 同步非阻塞和多執行緒+同步阻塞

高併發的程式一般使用同步非阻塞方式而非多執行緒 + 同步阻塞方式。要理解這一點,首先要扯到併發和並行的區別。比如去某部門辦事需要依次去幾個視窗,辦事大廳裡的人數就是併發數,而視窗個數就是並行度。也就是說併發數是指同時進行的任務數(如同時服務的 http 請求),而並行數是可以同時工作的物理資源數量(如 cpu 核數)。通過合理排程任務的不同階段,併發數可以遠遠大於並行度,這就是區區幾個 cpu 可以支援上萬個使用者併發請求的奧秘。在這種高併發的情況下,為每個任務(使用者請求)建立乙個程序或執行緒的開銷非常大。而同步非阻塞方式可以把多個 io 請求丟到後台去,這就可以在乙個程序裡服務大量的併發 io 請求。

首先開啟套接字的訊號驅動式io功能,並且通過sigaction系統呼叫安裝乙個訊號處理函式,該函式呼叫將立即返回,當前程序沒有被阻塞,繼續工作;當資料報準備好的時候,核心則為該程序產生sigio的訊號,隨後既可以在訊號處理函式中呼叫recvfrom讀取資料報,並且通知主迴圈資料已經準備好等待處理,也可以通知主迴圈讓它讀取資料報;(其實就是乙個待讀取的通知和待處理的通知);

我們呼叫aio_read函式,給核心傳遞描述符、緩衝區指標、緩衝區大小和檔案偏移,並且告訴核心當整個操作完成時如何通知我們。該函式呼叫後立即返回,不被阻塞;

原文:

總結阻塞和非阻塞,同步和非同步

例子 故事 老王燒開水。出場人物 老張,水壺兩把 普通水壺,簡稱水壺 會響的水壺,簡稱響水壺 老王想了想,有好幾種等待方式 1.老王用水壺煮水,並且站在那裡,不管水開沒開,每隔一定時間看看水開了沒。同步阻塞 老王想了想,這種方法不夠聰明。2.老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網...

阻塞和非阻塞,同步和非同步 總結

故事 老王燒開水。出場人物 老張,水壺兩把 普通水壺,簡稱水壺 會響的水壺,簡稱響水壺 老王想了想,有好幾種等待方式 1.老王用水壺煮水,並且站在那裡,不管水開沒開,每隔一定時間看看水開了沒。同步阻塞 老王想了想,這種方法不夠聰明。2.老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網,但是...

同步 非同步 阻塞和非阻塞

同步 非同步 阻塞和非阻塞 在進行windowsapi winsock 網路程式設計時,我們常常見到同步 非同步 阻塞和非阻塞四種呼叫方式。這些方式其實都可以擴充套件為廣義的概念,幫助我們理解多執行緒,多程序,實時作業系統等更廣的概念。同步 synchronic 所謂同步,就是在發出乙個功能呼叫時,...