linux 中阻塞與非阻塞 同步與異步

?

簡單點說: 阻塞就是干不完不準回來, 非阻塞就是你先干,我先看看有其他事沒有,完了告訴我一聲。

我們拿最常用的send和recv兩個函數來說吧。比如你調用send函數發送一定的Byte,在系統內部send做的工作其實只是把數據傳輸(Copy)到TCP/IP協議棧的輸出緩沖區,它執行成功并不代表數據已經成功的發送出去了,如TCP/IP協議棧沒有足夠的可用緩沖區來保存你Copy過來的數據的話,這時候就體現出阻塞和非阻塞的不同之處了:對于阻塞模式的socket,send函數將不返回,直到系統緩沖區有足夠的空間把你要發送的數據Copy過去以后才返回。而對于非阻塞的socket來說,send會立即返回,WSAEWOULDDBLOCK告訴調用者說:"發送操作被阻塞了!!!你想辦法處理吧。" 對于recv函數,同樣道理,該函數的內部工作機制其實是在等待TCP/IP協議棧的接收緩沖區通知它說:“嗨,你的數據來了。”對于阻塞模式的socket來說,如果TCP/IP協議棧的接收緩沖區沒有通知一個結果給它,它就一直不返回,耗費著系統資源。對于非阻塞模式的socket,該函數會馬上返回,然后告訴你:WSAEWOULDDBLOCK—"現在沒有數據,回頭再來看看" 。

在進行網絡編程時,我們常常見到同步、異步、阻塞和非阻塞四種調用方式。這些方式彼此概念并不好理解。下面是我對這些術語的理解。同步、異步指的是通信模式,而阻塞和非阻塞指的是在接收和發送時是否等待動作完成才返回,所以不能混淆這四個詞。通信的同步,主要是指客戶端在發送請求后,必須得在服務端有回應后才發送下一個請求。所以這個時候的所有請求將會在服務端得到同步;其次是通信的異步,指客戶端在發送請求后,不必等待服務端的回應就可以發送下一個請求,這樣對于所有的請求動作來說將會在服務端得到異步,這條請求的鏈路就象是一個請求隊列,所有的動作在這里不會得到同步的。阻塞和非阻塞只是應用在請求的讀取和發送。在實現過程中,如果服務端是異步的話,客戶端也是異步的話,通信效率會很高,但如果服務端在請求的返回時也是返回給請求的鏈路時,客戶端是可以同步的,這種情況下,服務端是兼容同步和異步的。相反,如果客戶端是異步而服務端是同步的也不會有問題,只是處理效率低了些。
在說到同步和異步的區別之前我先舉一個簡單的例子:

同步.一條馬路,只能開一輛車,等這個車開走了,才能開另一輛.
異步.一條馬路,隨便開多少車.
同步:所謂同步,就是在發出一個功能調用時,在沒有得到結果之前,該調用就不返回。按照這個定義,其實絕大多數函數都是同步調用(例如sin, isdigit等)。但是一般而言,我們在說同步、異步的時候,特指那些需要其他部件協作或者需要一定時間完成的任務。最常見的例子就是 SendMessage。該函數發送一個消息給某個窗口,在對方處理完消息之前,這個函數不返回。當對方處理完畢以后,該函數才把消息處理函數所返回的 LRESULT值返回給調用者。

異步:異步的概念和同步相對。當一個異步過程調用發出后,調用者不能立刻得到結果。實際處理這個調用的部件在完成后,通過狀態、通知和回調來通知調用者。以CAsycSocket類為例(注意,CSocket從CAsyncSocket派生,但是其功能已經由異步轉化為同步),當一個客戶端通過調用 Connect函數發出一個連接請求后,調用者線程立刻可以朝下運行。當連接真正建立起來以后,socket底層會發送一個消息通知該對象。這里提到執行部件和調用者通過三種途徑返回結果:狀態、通知和回調。可以使用哪一種依賴于執行部件的實現,除非執行部件提供多種選擇,否則不受調用者控制。如果執行部件用狀態來通知,那么調用者就需要每隔一定時間檢查一次,效率就很低(有些初學多線程編程的人,總喜歡用一個循環去檢查某個變量的值,這其實是一種很嚴重的錯誤)。如果是使用通知的方式,效率則很高,因為執行部件幾乎不需要做額外的操作。至于回調函數,其實和通知沒太多區別。

阻塞:阻塞調用是指調用結果返回之前,當前線程會被掛起。函數只有在得到結果之后才會返回。有人也許會把阻塞調用和同步調用等同起來,實際上他是不同的。對于同步調用來說,很多時候當前線程還是激活的,只是從邏輯上當前函數沒有返回而已。例如,我們在CSocket中調用Receive函數,如果緩沖區中沒有數 據,這個函數就會一直等待,直到有數據才返回。而此時,當前線程還會繼續處理各種各樣的消息。如果主窗口和調用函數在同一個線程中,除非你在特殊的界面操函數中調用,其實主界面還是應該可以刷新。socket接收數據的另外一個函數recv則是一個阻塞調用的例子。當socket工作在阻塞模式的時候,如果沒有數據的情況下調用該函數,則當前線程就會被掛起,直到有數據為止。

非阻塞:非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回。對象的阻塞模式和阻塞函數調用對象是否處于阻塞模式和函數是不是阻塞調用有很強的相關性,但是并不是一一對應的。阻塞對象上可以有非阻塞的調用方式,我們可以通過一定的API去輪詢狀態,在適當的時候調用阻塞函數,就可以避免阻塞。而對于非阻塞對象,調用特殊的函數也可以進入阻塞調用。函數select就是這樣的一個例子。阻塞通信通過重疊通信和計算在許多系統能提高性能。由一個智能通信控制器自動地執行通信的系統是真實的。輕-重線索是取得這種重疊的一種機制。導致好性能的一個可選的機制是使用非阻塞通信。一個阻塞發送開始調用初始化這個發送操作,但不完成它。在這個消息被從這個發送緩存拷出以前,這個發送開始調用將返回。需要一個獨立的“發送完成”調用完成這個通信,例如,檢驗從發送緩存拷出的數據。用適當的硬件,在發送被初始化后和它完成以前,來自發送者存儲的數據轉換 可以和在發送者完成的計算同時進行。類似地,一個非阻塞“接收開始調用”初始化這個接收操作, 但不完成它。在一個消息被存入這個接收緩存以前,這個調用將返回。須要一個獨立的“接收完成”調用完成這個接收操作,并檢驗被接收到這個接收緩存的數據。用適當的硬件,在接收操作初始化后和它完成以前,到接收者存儲的數據轉換可以和計算同時進行。非阻塞接收的使用雖著信息較早地在接收緩存位置被提供,也可以避免系統緩存和存儲器到存儲器拷貝。 非阻塞發送開始調用能使用與阻塞發送一樣的四種模式: 標準, 緩存, 同步和準備好模式。這些具有同樣的意義。無論一個匹配接收是否已登入,能開始除“準備好”以外的所有模式的發送;只要一個匹配接收已登入,就能開始一個非阻塞“準備好”發送。在所有情況下,發送開始調用是局部的:無論其它進程的狀態如何,它立刻返回。如果這個調用使得一些系統資源用完,那么它將失敗并返回 一個錯誤代碼。高質量的MPI實現應保證這種情況只在“病態”時發生。即,一個MPI實現將能支持大數量掛起非阻塞操作。當數據已被從發送緩存拷出時,這個發送完成調用返回。它可以帶有附加的意義,這取決于發送模式。如果發送模式是“同步的”,那么只有一個匹配接收已開始這個發送才能完成。即,一個接收已被登入,并已和這個發送匹配。這時,這個發送完成調用是非局部的。注意,在接收完成調用發生以前,如果一個同步、非阻塞發送和一個非阻塞接收匹配, 它可以完成。(發送者一“知道”轉換將結束,它就能完成,但在接收者“知道”轉換將結束以前)。如果發送模式是“緩存”,并沒有掛起接收,那么消息必須被緩存。這時,發送完成調用是局部的,而且無論一個匹配接收的狀態如何,它必須成功。如果發送模式是標準的,同時這個消息被緩存,那么在一個匹配接收發生以前,發送結束調用可以返回。另一方面,發送完成直到一個匹配接收發生才可以完成,并且這個消息已被拷到接收緩存。非阻塞發送能被用阻塞接收匹配,反過來也可以。給用戶的建議. 一個發送操作的完成, 對于標準模式可以被延遲, 對于同部模式必須延遲, 直到一個匹配接收登入。這兩種情況下非阻塞發送的使用允許發送者提前于接收者進行,以便在兩進程的速度方面,計算更容忍波動。緩存和準備好模式中的非阻塞發送有一個更有限的影響。一可能一個非阻塞發送將返回,而一個阻塞發送將在數據被從發送者存儲拷出后返回。只要在數據拷貝能和計算同時的情況下,非阻塞發送的使用有優點。消息發送模式隱含著由發送者初始化通信。當發送者初始化通信(數據被直接移到接收緩存, 并不要求排隊一個掛起發送請求) 時,如果一個接收已登入,這個通信一般將有較低的額外負擔。但是,只在匹配發送已發生后,一個接收操作能完成。當非阻塞接收等待發送時,沒有阻塞接收,它的使用允許得到較低的通信額外負擔。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/444990.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/444990.shtml
英文地址,請注明出處:http://en.pswp.cn/news/444990.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

leecode62 不同路徑

示例 1: 輸入: m 3, n 2 輸出: 3 解釋: 從左上角開始,總共有 3 條路徑可以到達右下角。 1. 向右 -> 向右 -> 向下 2. 向右 -> 向下 -> 向右 3. 向下 -> 向右 -> 向右 示例 2: 輸入: m 7, n 3 輸出: 28 思路:太過于簡單&#xf…

數據庫的查詢優化建議整理

從大多數數據庫應用系統的實例來看,查詢操作在各種數據庫操作中所占據的比重最大,而查詢操作所基于的SELECT語句在SQL語句中又是代價最大的語句。 查詢語句(SELECT)的優化建議 (1)、合理使用索引:where子句中變量順序應與索引字鍵順序相同。 如:create index test_idx…

Github(4)-遠程操作

使用github 托管代碼簡單使用教程--遠程操作3.連接本地倉庫與遠程倉庫3.1 git clone 克隆實現鏈接3.2 git remote add origin4.遠程操作4.1 git checkout -b 切換分支14.2 git branch 查看分支4.3 git merge 合并分支4.3.1 step1:切換成主分支4.3.2 step2&#xff1…

leetcode64 最小路徑和

給定一個包含非負整數的 m x n 網格,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和為最小。 說明:每次只能向下或者向右移動一步。 示例: 輸入: [ [1,3,1], [1,5,1], [4,2,1] ] 輸出: 7 解釋: 因為路徑 1→3→1→1→1 的總…

online游戲服務器架構--網絡架構

啟動:父進程啟動;子進程啟動;網絡架構。 每個父進程攜帶N個子進程,子進程負責處理業務邏輯和其它數據,而父進程只是將客戶端的請求路由到各個子進程,路由的策略非常簡單,父進程將請求包按照輪流…

online游戲服務器架構—用戶登錄數據組織 .

sprite_t類型的數據結構是核心數據結構,每一個登錄用戶對應一個,它的初始化在用戶登錄的時候,此后一直到用戶退出或者離線一直保存在系統內存當中,在此過程中該sprite_t數據結構被保存在兩個哈希表當中,一個是以用戶的…

leetcode300 最長上升子序列

經典題&#xff0c;不解釋&#xff0c;可以看我之前文章。 普通dp public class Solution {public int lengthOfLIS(int[] nums) {if (nums.length 0) {return 0;}int[] dp new int[nums.length];dp[0] 1;int maxans 1;for (int i 1; i < dp.length; i) {int maxval …

Github(5)-開源開發-常見錯誤

使用github 托管代碼簡單使用教程--開源開發-常見錯誤5. github開源開發6. 報錯log6.1 fatal: remote origin already exists.6.2 There is no tracking information for the current branch.6.標簽管理廖雪峰老師博文學習筆記&#xff1a;https://www.liaoxuefeng.com/wiki/89…

online游戲服務器架構--數據庫及事件相關 .

Online服務器的第三部分就是數據層&#xff0c;send_request_to_db開始了數據層的處理邏輯&#xff1a; int send_request_to_db(int cmd, sprite_t* p, int body_len, const void* body_buf, uint32_t id)&#xff1b; 在該函數里首先以懶惰的方式連接數據庫服務器&#xff…

leecode5 最長回文子串

給定一個字符串 s&#xff0c;找到 s 中最長的回文子串。你可以假設 s 的最大長度為 1000。 示例 1&#xff1a; 輸入: "babad" 輸出: "bab" 注意: "aba" 也是一個有效答案。 示例 2&#xff1a; 輸入: "cbbd" 輸出: "bb"…

libxml解析xml文件的一些總結

libxml -- 解析 XML 文檔XML 介紹&#xff1a;XML 和 DOMlibxml 介紹 數據類型 — xmlChar數據結構 創建 XML 文檔解析 XML 文檔修改 xml 文檔Xpath — 處理大型 XML 文檔libxml2 庫函數要注意的函數讀取 xml 文件xml 操作基本結構及其指針類型根節點相關函數 創建子節點相關函…

Linux(7)-正則表達式

正則表達式demo1:在某個文件中尋找命令seddemo2:尋找8位電話號碼正則表達式&#xff1a;用來描述或者匹配某一系列符合某個句法隊則的字符串或者單個字符串。最初正則表達式&#xff0c;出現在自動控制理論和形式化語言理論中。 Linux 中 find grep sed ls命令都支持正則表達式…

服務器端開發的一些建議

摘要: 本文作為游戲服務器端開發的基本大綱&#xff0c;是游戲實踐開發中的總結。第一部分專業基礎&#xff0c;用于指導招聘和實習考核&#xff0c; 第二部分游戲入門&#xff0c;講述游戲服務器端開發的基本要點&#xff0c;第三部分服務端架構&#xff0c;介紹架構設計中的一…

leetcode63 不同路徑II

一個機器人位于一個 m x n 網格的左上角 &#xff08;起始點在下圖中標記為“Start” &#xff09;。 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角&#xff08;在下圖中標記為“Finish”&#xff09;。 現在考慮網格中有障礙物。那么從左上角到右下角將…

小談Online-game服務器端設計(1、2)

談這個話題之前&#xff0c;首先要讓大家知道&#xff0c;什么是服務器。在網絡游戲中&#xff0c;服務器所扮演的角色是同步&#xff0c;廣播和服務器主動的一些行為&#xff0c;比如說天氣&#xff0c;NPC AI之類的&#xff0c;之所以現在的很多網絡游戲服務器都需要負擔一些…

Linux(8)-Linux下的編程開發-C/C++、PHP、JAVA概述

Linux下的編程開發1.C/C語言開發環境的搭建2.PHP開發環境搭建3.JAVA開發環境搭建1.C/C語言開發環境的搭建 方式1:文本編輯器編譯器&#xff08;gcc/g&#xff09; Ubuntu 下常用的文本編輯器&#xff1a; Gedit–語法高亮Vim–vi(無比強大無比難用)的改進。字符界面/圖形界面…

leetcode55 跳躍游戲 秒殺所有答案

給定一個非負整數數組&#xff0c;你最初位于數組的第一個位置。 數組中的每個元素代表你在該位置可以跳躍的最大長度。 判斷你是否能夠到達最后一個位置。 示例 1: 輸入: [2,3,1,1,4] 輸出: true 解釋: 我們可以先跳 1 步&#xff0c;從位置 0 到達 位置 1, 然后再從位置 …

小談Online-game服務器端設計(3)

下面我想來談談關于服務器上NPC的設計以及NPC智能等一些方面涉及到的問題。首先&#xff0c;我們需要知道什么是NPC&#xff0c;NPC需要做什么。NPC的全稱是&#xff08;Non-Player Character&#xff09;&#xff0c;很顯然&#xff0c;他是一個character&#xff0c;但不是玩…

小談Online-game服務器端設計(4)

在這一章節&#xff0c;我想談談關于服務器端的腳本的相關設計。因為在上一章節里面&#xff0c;談NPC智能相關的時候已經接觸到一些腳本相關的東東了。還是先來談談腳本的作用吧。   在基于編譯的服務器端程序中&#xff0c;是無法在程序的運行過程中構建一些東西的&#xf…

leetcode45 跳躍游戲II 秒殺所有答案

給定一個非負整數數組&#xff0c;你最初位于數組的第一個位置。 數組中的每個元素代表你在該位置可以跳躍的最大長度。 你的目標是使用最少的跳躍次數到達數組的最后一個位置。 示例: 輸入: [2,3,1,1,4] 輸出: 2 解釋: 跳到最后一個位置的最小跳躍數是 2。 從下標為 …