網絡IO模型

網絡包接收流程

網絡包接收流程.jpg

01.當網絡數據幀通過網絡傳輸到達網卡時蛤袒,網卡會將網絡數據幀通過DMA拷貝的方式放到DMA環(huán)形緩沖區(qū)RingBuffer中统阿;

環(huán)形緩沖區(qū) RingBuffer是網卡在啟動的時候分配和初始化的環(huán)形緩沖隊列钝凶;當RingBuffer滿的時候叹坦,新來的數據包就會被丟棄跪解;我們可以通過ifconfig命令查看網卡收發(fā)數據包的情況,其中overruns數據項表示當RingBuffer滿時被丟棄的數據包跌榔,如果發(fā)現出現丟包情況,可以通過ethtool命令來增大RingBuffer長度 捶障;


02.當DMA操作完成時僧须,網卡會向CPU發(fā)起一個硬中斷,告訴CPU有網絡數據到達项炼;CPU調用網卡驅動注冊的硬中斷響應程序担平; 網卡硬中斷響應程序會為網絡數據幀創(chuàng)建內核數據結構sk_buffer,并將網絡數據幀拷貝到sk_buffer中锭部;然后發(fā)起軟中斷請求暂论,通知內核有新的網絡數據幀到達 ;

緩沖區(qū)sk_buff拌禾,是一個維護網絡幀結構的雙向鏈表取胎,鏈表中的每一個元素都是一個網絡幀;雖然 TCP/IP 協議棧分了好幾層,但上下不同層之間的傳遞闻蛀,實際上只需要操作這個數據結構中的指針匪傍,而無需進行數據復制;


03.內核線程ksoftirqd發(fā)現軟中斷請求觉痛,調用網卡驅動注冊的poll函數役衡;poll函數將sk_buffer中的網絡數據包送到內核協議棧中注冊的ip_rcv函數中;

每個CPU會綁定一個ksoftirqd內核線程專門用來處理軟中斷響應秧饮;2個 CPU 時映挂,就會有 ksoftirqd/0ksoftirqd/1這兩個內核線程 ;

這里有個事情需要注意下: 網卡接收到數據后盗尸,當DMA拷貝完成時柑船,向CPU發(fā)出硬中斷,這時哪個CPU上響應了這個硬中斷泼各,那么在網卡硬中斷響應程序中發(fā)出的軟中斷請求也會在這個CPU綁定的ksoftirqd線程中響應鞍时;所以如果發(fā)現Linux軟中斷,CPU消耗都集中在一個核上的話扣蜻,那么就需要調整硬中斷的CPU親和性逆巍,來將硬中斷打散到不同的CPU核上去


04.在ip_rcv函數即網絡層中,取出數據包的IP頭莽使,判斷該數據包下一跳的走向锐极,如果數據包是發(fā)送給本機的,則取出傳輸層的協議類型(TCP或者UDP)芳肌,并去掉數據包的IP頭灵再,將數據包交給傳輸層處理;

傳輸層的處理函數:TCP協議對應內核協議棧中注冊的tcp_rcv函數亿笤,UDP協議對應內核協議棧中注冊的udp_rcv函數翎迁;


05.當我們采用的是TCP協議時,數據包到達傳輸層時净薛,會在內核協議棧中的tcp_rcv函數處理汪榔,在tcp_rcv函數中去掉TCP頭,根據四元組(源IP,源端口,目的IP,目的端口)查找對應的Socket肃拜,如果找到對應的Socket則將網絡數據包中的傳輸數據拷貝到Socket中的接收緩沖區(qū)中痴腌;如果沒有找到,則發(fā)送一個目標不可達的icmp包燃领;


06.當我們程序通過系統(tǒng)調用read讀取Socket接收緩沖區(qū)中的數據時衷掷,如果接收緩沖區(qū)中沒有數據,那么應用程序就會在系統(tǒng)調用上阻塞柿菩,直到Socket接收緩沖區(qū)有數據,然后CPU內核空間Socket接收緩沖區(qū))的數據拷貝到用戶空間雨涛,最后系統(tǒng)調用read返回枢舶,應用程序讀取數據 懦胞;


網絡包發(fā)送流程

網絡包發(fā)送流程.jpg

01.當我們在應用程序中調用send系統(tǒng)調用發(fā)送數據時,由于是系統(tǒng)調用所以線程會發(fā)生一次用戶態(tài)到內核態(tài)的轉換凉泄,在內核中首先根據fd將真正的Socket找出躏尉,這個Socket對象中記錄著各種協議棧的函數地址,然后構造struct msghdr對象后众,將用戶需要發(fā)送的數據全部封裝在這個struct msghdr結構體中胀糜;


02.調用內核協議棧函數inet_sendmsg,發(fā)送流程進入內核協議棧處理蒂誉;在進入到內核協議棧之后教藻,內核會找到Socket上的具體協議的發(fā)送函數;比如:我們使用的是TCP協議右锨,對應的TCP協議發(fā)送函數是tcp_sendmsg括堤,如果是UDP協議的話,對應的發(fā)送函數為udp_sendmsg绍移;


03.在TCP協議的發(fā)送函數tcp_sendmsg中悄窃,創(chuàng)建內核數據結構sk_buffer,將struct msghdr結構體中的發(fā)送數據拷貝到sk_buffer中蹂窖;調用tcp_write_queue_tail函數獲取Socket發(fā)送隊列中的隊尾元素轧抗,將新創(chuàng)建的sk_buffer添加到Socket發(fā)送隊列(雙向鏈表)的尾部;

發(fā)送流程走到這里瞬测,用戶要發(fā)送的數據總算是從用戶空間拷貝到了內核中横媚,這時雖然發(fā)送數據已經拷貝到了內核Socket中的發(fā)送隊列中,但并不代表內核會開始發(fā)送涣楷,因為TCP協議流量控制擁塞控制分唾,用戶要發(fā)送的數據包并不一定會立馬被發(fā)送出去,需要符合TCP協議的發(fā)送條件狮斗;如果沒有達到發(fā)送條件绽乔,那么本次send系統(tǒng)調用就會直接返回 ; 如果符合發(fā)送條件碳褒,則開始調用tcp_write_xmit內核函數折砸;在這個函數中,會循環(huán)獲取Socket發(fā)送隊列中待發(fā)送的sk_buffer沙峻,然后進行擁塞控制以及滑動窗口的管理睦授, 將從Socket發(fā)送隊列中獲取到的sk_buffer重新拷貝一份,設置sk_buffer副本中的TCP HEADER 摔寨;其實在 sk_buffer 內部其實包含了網絡協議中所有的 header去枷,在設置 TCP HEADER的時候,只是把指針指向 sk_buffer的合適位置,后面再設置 IP HEADER的時候删顶,在把指針移動一下就行竖螃,避免頻繁的內存申請和拷貝,效率很高逗余;


04.當設置完TCP頭后特咆,內核協議棧傳輸層的事情就做完了,下面通過調用ip_queue_xmit內核函數录粱,正式來到內核協議棧網絡層的處理腻格;

  1. sk_buffer中的指針移動到IP頭位置上,設置IP頭 啥繁;
  1. 執(zhí)行netfilters過濾鸥滨,過濾通過之后终吼,如果數據大于 MTU的話杠氢,則執(zhí)行分片 昂勉;
  1. 檢查Socket中是否有緩存路由表,如果沒有的話宪睹,則查找路由項愁茁,并緩存到Socket中;接著在把路由表設置到sk_buffer中 亭病;

05.內核協議棧網絡層的事情處理完后鹅很,現在發(fā)送流程進入了到了鄰居子系統(tǒng)鄰居子系統(tǒng)位于內核協議棧中的網絡層網絡接口層之間罪帖,用于發(fā)送ARP請求獲取MAC地址促煮,然后將sk_buffer中的指針移動到MAC頭位置,填充MAC頭整袁;


06.經過鄰居子系統(tǒng)的處理菠齿,現在sk_buffer中已經封裝了一個完整的數據幀,隨后內核將sk_buffer交給網絡設備子系統(tǒng)進行處理坐昙;

  1. 選擇發(fā)送隊列(RingBuffer)绳匀,因為網卡擁有多個發(fā)送隊列,所以在發(fā)送前需要選擇一個發(fā)送隊列
  1. sk_buffer添加到發(fā)送隊列中炸客;
  1. 循環(huán)從發(fā)送隊列(RingBuffer)中取出sk_buffer疾棵,調用內核函數sch_direct_xmit發(fā)送數據,其中會調用網卡驅動程序來發(fā)送數據 痹仙;

07.現在發(fā)送流程到了網卡真實發(fā)送數據的階段是尔,無論是用戶線程的內核態(tài)還是觸發(fā)NET_TX_SOFTIRQ類型的軟中斷在發(fā)送數據的時候最終會調用到網卡的驅動程序函數dev_hard_start_xmit來發(fā)送數據;在網卡驅動程序函數dev_hard_start_xmit中會將sk_buffer映射到網卡可訪問的內存 DMA 區(qū)域开仰,最終網卡驅動程序通過DMA的方式將數據幀通過物理網卡發(fā)送出去拟枚;


08.當數據發(fā)送完畢后薪铜,還有最后一項重要的工作,就是清理工作梨州;數據發(fā)送完畢后痕囱,網卡設備會向CPU發(fā)送一個硬中斷,CPU調用網卡驅動程序注冊的硬中斷響應程序暴匠,在硬中斷響應中觸發(fā)NET_RX_SOFTIRQ類型的軟中斷,在軟中斷的回調函數igb_poll中清理釋放 sk_buffer傻粘,清理網卡發(fā)送隊列(RingBuffer)每窖,解除 DMA映射;

無論硬 中斷是因為有數據要接收弦悉,還是說發(fā)送完成通知窒典,從硬中斷觸發(fā)的軟中斷都是 NET_RX_SOFTIRQ; 這里釋放清理的只是sk_buffer的副本稽莉,真正的sk_buffer現在還是存放在Socket的發(fā)送隊列中瀑志;它得等收到對方ACK 之后才會真正刪除;


阻塞非阻塞

將接收網絡包流程分為數據準備階段數據拷貝階段 污秆;阻塞與非阻塞的區(qū)別主要發(fā)生在數據準備階段劈猪,同步與異步的區(qū)別主要發(fā)生在數據拷貝階段

數據準備階段:在這個階段良拼,網絡數據包到達網卡战得,通過DMA的方式將數據包拷貝到內存中,然后經過硬中斷庸推,軟中斷常侦,接著通過內核線程ksoftirqd經過內核協議棧的處理,最終將數據發(fā)送到內核Socket的接收緩沖區(qū)中贬媒;

數據拷貝階段:當數據到達內核Socket的接收緩沖區(qū)中時聋亡,此時數據存在于內核空間中,需要將數據拷貝到用戶空間中际乘,才能夠被應用程序讀绕戮蟆;

阻塞: 當應用程序發(fā)起系統(tǒng)調用read時蚓庭,線程從用戶態(tài)轉為內核態(tài)致讥,讀取內核Socket的接收緩沖區(qū)中的網絡數據;如果這時內核Socket的接收緩沖區(qū)沒有數據器赞,那么線程就會一直等待垢袱,直到Socket接收緩沖區(qū)有數據為止;隨后將數據從內核空間拷貝到用戶空間港柜,系統(tǒng)調用read返回 请契;

非阻塞:當應用程序發(fā)起系統(tǒng)調用read時咳榜,線程從用戶態(tài)轉為內核態(tài),讀取內核Socket的接收緩沖區(qū)中的網絡數據爽锥;如果這時內核Socket的接收緩沖區(qū)沒有數據涌韩,應用程序不會等待,系統(tǒng)調用直接返回錯誤標志EWOULDBLOCK 氯夷,直到Socket接收緩沖區(qū)有數據為止臣樱;隨后將數據從內核空間拷貝到用戶空間,系統(tǒng)調用read返回 腮考;


同步與異步

同步:在數據準備好后雇毫,是由用戶線程的內核態(tài)來執(zhí)行第二階段;所以應用程序會在第二階段發(fā)生阻塞踩蔚,直到數據從內核空間拷貝到用戶空間棚放,系統(tǒng)調用才會返回;Linux下的 epollMac 下的 kqueue都屬于同步 IO馅闽;

異步:在數據準備好后飘蚯,是由內核來執(zhí)行第二階段的數據拷貝操作;當內核執(zhí)行完第二階段福也,會通知用戶線程IO操作已經完成局骤,并將數據回調給用戶線程;所以在異步模式下 數據準備階段數據拷貝階段均是由內核來完成拟杉,不會對應用程序造成任何阻塞庄涡;


網絡IO模型

在進行網絡IO操作時,用什么樣的IO模型來讀寫數據將在很大程度上決定了網絡框架的IO性能搬设,所以IO模型的選擇是構建一個高性能網絡框架的基礎穴店,在《UNIX 網絡編程》一書中介紹了五種IO模型:阻塞IO,非阻塞IO,IO多路復用,信號驅動IO,異步IO,每一種IO模型的出現都是對前一種的升級優(yōu)化拿穴;


阻塞IO(BIO)

阻塞讀: 當用戶線程發(fā)起read系統(tǒng)調用泣洞,用戶線程從用戶態(tài)切換到內核態(tài),在內核中去查看Socket接收緩沖區(qū)是否有數據到來 默色; Socket接收緩沖區(qū)中有數據 球凰,則用戶線程在內核態(tài)將內核空間中的數據拷貝到用戶空間,系統(tǒng)IO調用返回腿宰; Socket接收緩沖區(qū)中無數據呕诉,則用戶線程讓出CPU,進入阻塞狀態(tài)吃度,當數據到達Socket接收緩沖區(qū)后甩挫,內核喚醒阻塞狀態(tài)中的用戶線程進入就緒狀態(tài),隨后經過CPU的調度獲取到CPU quota進入運行狀態(tài)椿每,將內核空間的數據拷貝到用戶空間伊者,隨后系統(tǒng)調用返回英遭;

阻塞寫: 當用戶線程發(fā)起send系統(tǒng)調用時,用戶線程從用戶態(tài)切換到內核態(tài)亦渗,將發(fā)送數據從用戶空間拷貝到內核空間中的Socket發(fā)送緩沖區(qū)中挖诸; 當Socket發(fā)送緩沖區(qū)能夠容納下發(fā)送數據時,用戶線程會將全部的發(fā)送數據寫入Socket緩沖區(qū)法精,然后執(zhí)行后續(xù)流程多律,最后返回; 當Socket發(fā)送緩沖區(qū)空間不夠亿虽,無法容納下全部發(fā)送數據時菱涤,用戶線程讓出CPU,進入阻塞狀態(tài)洛勉,直到Socket發(fā)送緩沖區(qū)能夠容納下全部發(fā)送數據時,內核喚醒用戶線程如迟,執(zhí)行后續(xù)發(fā)送流程收毫,最后返回;

阻塞IO模型:由于阻塞IO的讀寫特點殷勘,所以導致在阻塞IO模型下此再,每個請求都需要被一個獨立的線程處理;一個線程在同一時刻只能與一個連接綁定玲销,來一個請求输拇,服務端就需要創(chuàng)建一個線程用來處理請求,當客戶端請求的并發(fā)量突然增大時贤斜,服務端在一瞬間就會創(chuàng)建出大量的線程策吠,而創(chuàng)建線程是需要系統(tǒng)資源開銷的,這樣一來就會一瞬間占用大量的系統(tǒng)資源瘩绒;如果客戶端創(chuàng)建好連接后猴抹,但是一直不發(fā)數據,那么在空閑的這段時間內锁荔,服務端線程就會一直處于阻塞狀態(tài)蟀给,無法干其他的事情,CPU也無法得到充分的發(fā)揮阳堕,同時還會導致大量線程切換的開銷跋理;


非阻塞IO(NIO)

非阻塞讀: 當用戶線程發(fā)起非阻塞read系統(tǒng)調用時,用戶線程從用戶態(tài)轉為內核態(tài)恬总,在內核中去查看Socket接收緩沖區(qū)是否有數據到來前普; Socket接收緩沖區(qū)中無數據,系統(tǒng)調用立馬返回越驻,并帶有一個 EWOULDBLOCKEAGAIN錯誤汁政,這個階段用戶線程不會阻塞道偷,也不會讓出CPU,而是會繼續(xù)輪訓直到Socket接收緩沖區(qū)中有數據為止记劈; Socket接收緩沖區(qū)中有數據勺鸦,用戶線程在內核態(tài)會將內核空間中的數據拷貝到用戶空間,注意:這個數據拷貝階段目木,應用程序是阻塞的换途,當數據拷貝完成,系統(tǒng)調用返回 刽射;

非阻塞寫: 當用戶線程發(fā)起非阻塞send系統(tǒng)調用時军拟,當發(fā)送緩沖區(qū)中沒有足夠的空間容納全部發(fā)送數據時,非阻塞寫的特點是能寫多少寫多少誓禁,寫不下了懈息,就立即返回,并將寫入到發(fā)送緩沖區(qū)的字節(jié)數返回給應用程序摹恰,方便用戶線程不斷的輪訓嘗試將剩下的數據寫入發(fā)送緩沖區(qū)中 辫继;

非阻塞IO模型:阻塞IO模型最大的問題就是一個線程只能處理一個連接,如果這個連接上沒有數據的話俗慈,那么這個線程就只能阻塞在系統(tǒng)IO調用上姑宽,不能干其他的事情,這對系統(tǒng)資源來說闺阱,是一種極大的浪費炮车,同時大量的線程上下文切換,也是一個巨大的系統(tǒng)開銷 酣溃, 基于這個需求瘦穆,第一種解決方案非阻塞IO就出現了 ;基于以上非阻塞IO的特點救拉,我們就不必像阻塞IO那樣為每個請求分配一個線程去處理連接上的讀寫了难审,我們可以利用一個線程或者很少的線程,去不斷地輪詢每個Socket的接收緩沖區(qū)是否有數據到達亿絮,如果沒有數據告喊,不必阻塞線程,而是接著去輪詢下一個Socket接收緩沖區(qū)派昧,直到輪詢到數據后黔姜,處理連接上的讀寫或者交給業(yè)務線程池去處理),輪詢線程則繼續(xù)輪詢其他的Socket接收緩沖區(qū)蒂萎;


IO多路復用

select: select是操作系統(tǒng)內核提供給我們使用的一個系統(tǒng)調用秆吵,它解決了在非阻塞IO模型中需要不斷的發(fā)起系統(tǒng)IO調用去輪詢各個連接上的Socket接收緩沖區(qū)所帶來的用戶空間內核空間不斷切換的系統(tǒng)開銷,轉而交給內核來幫我們完成:

  1. 首先用戶線程在發(fā)起select系統(tǒng)調用的時候會阻塞在select系統(tǒng)調用上五慈,此時用戶線程從用戶態(tài)切換到了內核態(tài)完成了一次上下文切換纳寂;
  1. 用戶線程將需要監(jiān)聽的Socket對應的文件描述符fd數組通過select系統(tǒng)調用傳遞給內核主穗,此時用戶線程將用戶空間中的文件描述符fd數組拷貝到內核空間;
  1. 當用戶線程調用完select后開始進入阻塞狀態(tài)毙芜,內核開始輪詢遍歷fd數組忽媒,查看fd對應的Socket接收緩沖區(qū)中是否有數據到來,如果有數據到來腋粥,則將fd對應BitMap的值設置為1晦雨,如果沒有數據到來,則保持值為0 隘冲;
  1. 內核遍歷一遍fd數組后闹瞧,如果發(fā)現有些fd上有IO數據到來,則將修改后的fd數組返回給用戶線程展辞,此時會將fd數組從內核空間拷貝到用戶空間 奥邮;
  1. 當內核將修改后的fd數組返回給用戶線程后,用戶線程解除阻塞罗珍,由用戶線程開始遍歷fd數組然后找出fd數組中值為1Socket文件描述符漠烧,最后對這些Socket發(fā)起系統(tǒng)調用讀取數據 ;
  1. 由于內核在遍歷的過程中已經修改了fd數組靡砌,所以在用戶線程遍歷完fd數組后獲取到IO就緒的Socket后,就需要重置fd數組珊楼,并重新調用select傳入重置后的fd數組通殃,讓內核發(fā)起新的一輪遍歷輪詢 ;

雖然select解決了非阻塞IO模型中頻繁發(fā)起系統(tǒng)調用的問題厕宗,但是在整個select工作過程中画舌,我們還是看出了select有些不足的地方:(1)在發(fā)起select系統(tǒng)調用以及返回時,用戶線程各發(fā)生了一次用戶態(tài)內核態(tài)以及內核態(tài)用戶態(tài)的上下文切換開銷已慢,發(fā)生2次上下文切換曲聂;(2)在發(fā)起select系統(tǒng)調用以及返回時,用戶線程在內核態(tài)需要將文件描述符集合從用戶空間拷貝到內核空間佑惠,以及在內核修改完文件描述符集合后朋腋,又要將它從內核空間拷貝到用戶空間膜楷,發(fā)生2次文件描述符集合的拷貝;(3)雖然由原來在用戶空間發(fā)起輪詢優(yōu)化成了在內核空間發(fā)起輪詢但select不會告訴用戶線程到底是哪些Socket上發(fā)生了IO就緒事件,只是對IO就緒的Socket作了標記,用戶線程依然要遍歷文件描述符集合去查找具體IO就緒的Socket,時間復雜度依然為O(n) 洽洁;(4)內核會對原始的文件描述符集合進行修改,導致每次在用戶空間重新發(fā)起select調用時,都需要對文件描述符集合進行重置总放; (5)BitMap結構的文件描述符集合炬搭,長度為固定的1024衣形,所以只能監(jiān)聽0~1023的文件描述符 ;(6)select系統(tǒng)調用不是線程安全的句狼;

poll:poll相當于是改進版的select笋熬,select中使用的文件描述符集合是采用的固定長度為1024的BitMap結構的fd_set,而poll換成了pollfd結構沒有固定長度的數組腻菇,這樣就沒有了最大描述符數量的限制 胳螟;poll只是改進了select只能監(jiān)聽1024個文件描述符的數量限制,但是并沒有在性能方面做出改進筹吐,和select上本質并沒有多大差別 糖耸, 依然無法解決C10K問題 ;

epoll:

IO多路復用模型:雖然非阻塞IO模型與阻塞IO模型相比丘薛,減少了很大一部分的資源消耗和系統(tǒng)開銷嘉竟,但是它仍然有很大的性能問題,因為在非阻塞IO模型下洋侨,需要用戶線程去不斷地發(fā)起系統(tǒng)調用去輪訓Socket接收緩沖區(qū)舍扰,這就需要用戶線程不斷地從用戶態(tài)切換到內核態(tài),內核態(tài)切換到用戶態(tài)希坚,隨著并發(fā)量的增大边苹,這個上下文切換的開銷也是巨大的,所以單純的非阻塞IO模型還是無法適用于高并發(fā)的場景裁僧,只能適用于C10K以下的場景勾给;這就需要操作系統(tǒng)的內核來支持這樣的操作,我們可以把頻繁的輪詢操作交給操作系統(tǒng)內核來替我們完成锅知,這樣就避免了在用戶空間頻繁的去使用系統(tǒng)調用來輪詢所帶來的性能開銷;


信號驅動IO

在信號驅動IO模型下脓钾,用戶進程操作通過系統(tǒng)調用 sigaction 函數發(fā)起一個IO 請求售睹,在對應的socket注冊一個信號回調,此時不阻塞用戶進程可训,進程會繼續(xù)工作昌妹,當內核數據就緒時,內核就為該進程生成一個 SIGIO 信號握截,通過信號回調通知進程進行相關IO 操作 飞崖; 信號驅動 IO模型 相比于前三種 IO 模型,實現了在等待數據就緒時谨胞,進程不被阻塞固歪,主循環(huán)可以繼續(xù)工作,所以理論上性能更佳 ; 但是實際上牢裳,使用TCP協議通信時逢防,信號驅動IO模型幾乎不會被采用,因為信號IO在大量IO 操作時可能會因為信號隊列溢出導致沒法通知 蒲讯, SIGIO 信號是一種 Unix信號忘朝,信號沒有附加信息,如果一個信號源有多種產生信號的原因判帮,信號接收者就無法確定究竟發(fā)生了什么局嘁,而 TCP socket 生產的信號事件有七種之多,這樣應用程序收到 SIGIO晦墙,根本無從區(qū)分處理 悦昵; 但信號驅動IO模型可以用在 UDP通信上,因為UDP 只有一個數據請求事件偎痛,這也就意味著在正常情況下 UDP 進程只要捕獲 SIGIO 信號旱捧,就調用 read系統(tǒng)調用讀取到達的數據,如果出現異常踩麦,就返回一個異常錯誤 枚赡;

這里需要注意的是信號驅動式IO 模型依然是同步IO,因為它雖然可以在等待數據的時候不被阻塞谓谦,也不會頻繁的輪詢贫橙,但是當數據就緒,內核信號通知后反粥,用戶進程依然要自己去讀取數據卢肃,在數據拷貝階段發(fā)生阻塞


異步IO(AIO)

異步IO的系統(tǒng)調用需要操作系統(tǒng)內核來支持,目前只有Window中的IOCP實現了非常成熟的異步IO機制 才顿;


?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末莫湘,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子郑气,更是在濱河造成了極大的恐慌幅垮,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尾组,死亡現場離奇詭異忙芒,居然都是意外死亡,警方通過查閱死者的電腦和手機讳侨,發(fā)現死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門呵萨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人跨跨,你說我怎么就攤上這事潮峦。” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵跑杭,是天一觀的道長铆帽。 經常有香客問我,道長德谅,這世上最難降的妖魔是什么爹橱? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮窄做,結果婚禮上愧驱,老公的妹妹穿的比我還像新娘。我一直安慰自己椭盏,他們只是感情好组砚,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掏颊,像睡著了一般糟红。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乌叶,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天盆偿,我揣著相機與錄音,去河邊找鬼准浴。 笑死事扭,一個胖子當著我的面吹牛,可吹牛的內容都是我干的乐横。 我是一名探鬼主播求橄,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼葡公!你這毒婦竟也來了罐农?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤催什,失蹤者是張志新(化名)和其女友劉穎啃匿,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體蛆楞,經...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年夹厌,在試婚紗的時候發(fā)現自己被綠了豹爹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡矛纹,死狀恐怖臂聋,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤孩等,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布艾君,位于F島的核電站,受9級特大地震影響肄方,放射性物質發(fā)生泄漏冰垄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一权她、第九天 我趴在偏房一處隱蔽的房頂上張望虹茶。 院中可真熱鬧,春花似錦隅要、人聲如沸蝴罪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽要门。三九已至,卻和暖如春廓啊,著一層夾襖步出監(jiān)牢的瞬間欢搜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工崖瞭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留狂巢,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓书聚,卻偏偏與公主長得像唧领,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子雌续,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內容