日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

IO模型、IO多路复用

發(fā)布時(shí)間:2024/1/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IO模型、IO多路复用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

IO多路復(fù)用

  • 基礎(chǔ)概述
    • 用戶空間和內(nèi)核空間
    • PIO與DMA
    • 緩存IO和直接IO
      • 緩存IO
        • 優(yōu)點(diǎn)
        • 缺點(diǎn)
      • 直接IO
    • IO訪問方式
      • 磁盤IO
      • 網(wǎng)絡(luò)IO
      • 磁盤IO和網(wǎng)絡(luò)IO對(duì)比
    • Socket網(wǎng)絡(luò)編程
      • 客戶端
      • 服務(wù)端
    • 同步IO和異步IO
    • 阻塞IO和非阻塞IO
  • IO設(shè)計(jì)模式之Reactor和Proactor
    • 反應(yīng)器Reactor
      • 概述
      • 為什么使用Reactor模式
      • Reactor模式結(jié)構(gòu)
      • 業(yè)務(wù)流程及時(shí)序圖
    • Proactor模式
      • Proactor模式結(jié)構(gòu)
      • 業(yè)務(wù)流程及時(shí)序圖
    • Reactor和Proactor對(duì)比
      • 主動(dòng)和被動(dòng)
      • 實(shí)現(xiàn)
      • 優(yōu)點(diǎn)
      • 缺點(diǎn)
      • 適用場景
  • 漫談五種IO模型
    • 高性能IO模型淺析
    • IO模型舉例理解
      • 例1
      • 例2
    • 同步阻塞IO
    • 同步非阻塞IO
    • IO多路復(fù)用
    • 異步IO
  • Redis的IO多路復(fù)用技術(shù)
    • 為什么Redis中要使用I/O多路復(fù)用
    • epoll實(shí)現(xiàn)機(jī)制
    • redis epoll底層實(shí)現(xiàn)

基礎(chǔ)概述

用戶空間和內(nèi)核空間

  • Linux 中有兩個(gè)詞:User space (用戶空間)和 Kernel space (內(nèi)核空間)
  • 簡單說,Kernel space 是 Linux 內(nèi)核的運(yùn)行空間,User space 是用戶程序的運(yùn)行空間。為了安全起見,它們是隔離的,即使用戶的程序崩潰了,內(nèi)核也不受影響。
  • 虛擬內(nèi)存被操作系統(tǒng)劃分為兩塊:內(nèi)核空間和用戶空間,內(nèi)核空間是內(nèi)核代碼運(yùn)行的地方,用戶空間是用戶程序代碼運(yùn)行的地方。當(dāng)進(jìn)程運(yùn)行在內(nèi)核空間時(shí)就處于內(nèi)核態(tài),當(dāng)進(jìn)程運(yùn)行在用戶空間時(shí)就處于用戶態(tài)。
  • Kernel space 可以執(zhí)行任意命令,調(diào)用系統(tǒng)的一切資源;User space 只能執(zhí)行簡單的運(yùn)算,不能直接調(diào)用系統(tǒng)資源,必須通過系統(tǒng)接口(又稱 system call),才能向內(nèi)核發(fā)出指令。
  • 通過系統(tǒng)接口,進(jìn)程可以從用戶空間切換到內(nèi)核空間。例如:
str = "my string"; // 用戶空間 x = x + 2; file.write(str); // 切換到內(nèi)核空間 y = x + 4; // 切換到用戶空間
  • 上面代碼中,第一行和第二行都是簡單的賦值運(yùn)算,在 User space 執(zhí)行。第三行需要寫入文件,就要切換到Kernel space,因?yàn)橛脩舨荒苤苯訉懳募?#xff0c;必須通過內(nèi)核安排。第四行又是賦值運(yùn)算,就切換回 User space。
  • 查看 CPU 時(shí)間在 User space 與 Kernel Space 之間的分配情況,可以使用top命令。它的第三行輸出就是 CPU時(shí)間分配統(tǒng)計(jì)。
  • 這一行有 8 項(xiàng)統(tǒng)計(jì)指標(biāo):其中,第一項(xiàng) 0.7 us(user 的縮寫)就是 CPU 消耗在 User space 的時(shí)間百分比,第二項(xiàng) 0.3 sy(system 的縮寫)是消耗在 Kernel space 的時(shí)間百分比。
  • 其他 6 個(gè)指標(biāo)的含義:
  • ni :niceness 的縮寫,CPU 消耗在 nice 進(jìn)程(低優(yōu)先級(jí))的時(shí)間百分比。
  • id :idle 的縮寫,CPU 消耗在閑置進(jìn)程的時(shí)間百分比,這個(gè)值越低,表示 CPU 越忙。
  • wa :wait 的縮寫,CPU 等待外部 I/O 的時(shí)間百分比,這段時(shí)間 CPU 不能干其他事,但是也沒有執(zhí)行運(yùn)算,這個(gè)值太高就說明外部設(shè)備有問題。
  • hi :hardware interrupt 的縮寫,CPU 響應(yīng)硬件中斷請(qǐng)求的時(shí)間百分比。
  • si :software interrupt 的縮寫,CPU 響應(yīng)軟件中斷請(qǐng)求的時(shí)間百分比。
  • st :stole time 的縮寫,該項(xiàng)指標(biāo)只對(duì)虛擬機(jī)有效,表示分配給當(dāng)前虛擬機(jī)的 CPU 時(shí)間之中,被同一臺(tái)物理機(jī)上的其他虛擬機(jī)偷走的時(shí)間百分比。

PIO與DMA

  • PIO:我們拿磁盤來說,很早以前,磁盤和內(nèi)存之間的數(shù)據(jù)傳輸是需要CPU控制的,也就是說如果我們讀取磁盤文件到內(nèi)存中,數(shù)據(jù)需要經(jīng)過 CPU 存儲(chǔ)轉(zhuǎn)發(fā),這種方式稱為 PIO。顯然這種方式非常不合理,需要占用大量的CPU時(shí)間來讀取文件,造成文件訪問時(shí)系統(tǒng)幾乎停止響應(yīng)。
  • DMA:后來DMA(直接內(nèi)存訪問,Direct Memory Access)取代了PIO,它可以不經(jīng)過CPU而直接進(jìn)行磁盤和內(nèi)存(內(nèi)核空間)的數(shù)據(jù)交換。在DMA模式下,CPU只需要向DMA控制器下達(dá)指令,讓DMA控制器來處理數(shù)據(jù)在DMA模式下,CPU只需要向DMA控制器下達(dá)指令,讓DMA控制器來處理數(shù)據(jù)率,大大節(jié)省了系統(tǒng)資源,而它的傳輸速度與PIO的差異其實(shí)并不十分明顯,因?yàn)檫@主要取決于慢速設(shè)備的速度。

緩存IO和直接IO

  • 緩存IO:數(shù)據(jù)從磁盤先通過DMA copy到內(nèi)核空間,再從內(nèi)核空間通過cpu copy到用戶空間。
  • 直接IO:數(shù)據(jù)從磁盤通過DMA copy到用戶空間。

緩存IO

緩存I/O又被稱作標(biāo)準(zhǔn)I/O,大多數(shù)文件系統(tǒng)的默認(rèn)I/O操作都是緩存I/O。在Linux的緩存I/O機(jī)制中,數(shù)據(jù)先從磁盤復(fù)制到內(nèi)核空間的緩沖區(qū),然后從內(nèi)核空間緩沖區(qū)復(fù)制到應(yīng)用程序的地址空間。

  • 讀操作:操作系統(tǒng)檢查內(nèi)核的緩沖區(qū)有沒有需要的數(shù)據(jù),如果已經(jīng)緩存了,那么就直接從緩存中返回;否則從磁盤中讀取,然后緩存在操作系統(tǒng)的緩存中。
  • 寫操作:將數(shù)據(jù)從用戶空間復(fù)制到內(nèi)核空間的緩存中,這時(shí)對(duì)用戶程序來說寫操作就已經(jīng)完成,至于什么時(shí)候再寫到磁盤中由操作系統(tǒng)決定,除非顯示地調(diào)用了 sync 同步命令。【珍藏】linux 同步IO: sync、fsync與fdatasync

優(yōu)點(diǎn)

  • 在一定程度上分離了內(nèi)核空間和用戶空間,保護(hù)系統(tǒng)本身的運(yùn)行安全。
  • 可以減少讀盤的次數(shù),從而提高性能。

缺點(diǎn)

  • 在緩存 I/O 機(jī)制中,DMA 方式可以將數(shù)據(jù)直接從磁盤讀到頁緩存中,或者將數(shù)據(jù)從頁緩存直接寫回到磁盤上,而不能直接在應(yīng)用程序地址空間和磁盤之間進(jìn)行數(shù)據(jù)傳輸,這樣,數(shù)據(jù)在傳輸過程中需要在應(yīng)用程序地址空間(用戶空間)和緩存(內(nèi)核空間)之間進(jìn)行多次數(shù)據(jù)拷貝操作,這些數(shù)據(jù)拷貝操作所帶來的CPU以及內(nèi)存開銷是非常大的。

直接IO

直接IO就是應(yīng)用程序直接訪問磁盤數(shù)據(jù),而不經(jīng)過內(nèi)核緩沖區(qū),也就是繞過內(nèi)核緩沖區(qū),自己管理I/O緩存區(qū),這樣做的目的是減少一次從內(nèi)核緩沖區(qū)到用戶程序緩存的數(shù)據(jù)復(fù)制。

  • 引入內(nèi)核緩沖區(qū)的目的在于提高磁盤文件的訪問性能,因?yàn)楫?dāng)進(jìn)程需要讀取磁盤文件時(shí),如果文件內(nèi)容已經(jīng)在內(nèi)核緩沖區(qū)中,那么就不需要再次訪問磁盤;而當(dāng)進(jìn)程需要向文件中寫入數(shù)據(jù)時(shí),實(shí)際上只是寫到了內(nèi)核緩沖區(qū)便告訴進(jìn)程已經(jīng)寫成功,而真正寫入磁盤是通過一定的策略進(jìn)行延遲的。
  • 然而,對(duì)于一些較復(fù)雜的應(yīng)用,比如數(shù)據(jù)庫服務(wù)器,它們?yōu)榱顺浞痔岣咝阅?#xff0c;希望繞過內(nèi)核緩存區(qū),由自己在用戶態(tài)空間實(shí)現(xiàn)并管理I/O緩沖區(qū),包括緩存機(jī)制和寫延遲機(jī)制等,以支持獨(dú)特的查詢機(jī)制,比如數(shù)據(jù)庫可以根據(jù)更加合理的策略來提高查詢緩存命中率。另一方面,繞過內(nèi)核緩沖區(qū)也可以減少系統(tǒng)內(nèi)存的開銷,因?yàn)閮?nèi)核緩沖區(qū)本身就在使用系統(tǒng)內(nèi)存。
  • 應(yīng)用程序直接訪問磁盤數(shù)據(jù),不經(jīng)過操作系統(tǒng)內(nèi)核數(shù)據(jù)緩沖區(qū),這樣做的目的是減少一次從內(nèi)核緩沖區(qū)到用戶程序緩存的數(shù)據(jù)復(fù)制。這種方式通常是在對(duì)數(shù)據(jù)的緩存管理由應(yīng)用程序?qū)崿F(xiàn)的數(shù)據(jù)庫管理系統(tǒng)中。
  • 直接I/O的缺點(diǎn)就是如果訪問的數(shù)據(jù)不在應(yīng)用程序緩存中,那么每次數(shù)據(jù)都會(huì)直接從磁盤進(jìn)行加載,這種直接加載會(huì)非常慢。通常直接I/O根異步I/O結(jié)合使用會(huì)得到較好的性能


  • Linux提供了對(duì)這種需求的支持,即在 open() 系統(tǒng)調(diào)用中增加參數(shù)選項(xiàng) O_DIRECT,用它打開的文件便可以繞過內(nèi)核緩沖區(qū)的直接訪問,這樣便有效避免了CPU和內(nèi)存的多余時(shí)間開銷
  • 順便提一下,與O_DIRECT類似的一個(gè)選項(xiàng)是O_SYNC,后者只對(duì)寫數(shù)據(jù)有效,它將寫入內(nèi)核緩沖區(qū)的數(shù)據(jù)立即寫入磁盤,將機(jī)器故障時(shí)數(shù)據(jù)的丟失減少到最小,但是它仍然要經(jīng)過內(nèi)核緩沖區(qū)。

IO訪問方式

磁盤IO

  • 當(dāng)應(yīng)用程序調(diào)用read接口時(shí),操作系統(tǒng)檢查在內(nèi)核的高速緩存有沒有需要的數(shù)據(jù),如果已經(jīng)緩存了,那么就直接從緩存中返回,如果沒有,則從磁盤中讀取,然后緩存在操作系統(tǒng)的緩存中。
  • 應(yīng)用程序調(diào)用write接口時(shí),將數(shù)據(jù)從用戶地址空間復(fù)制到內(nèi)核地址空間的緩存中,這時(shí)對(duì)用戶程序來說,寫操作已經(jīng)完成,至于什么時(shí)候再寫到磁盤中,由操作系統(tǒng)決定,除非顯示調(diào)用了sync同步命令。

網(wǎng)絡(luò)IO

  • ① 操作系統(tǒng)將數(shù)據(jù)從磁盤復(fù)制到操作系統(tǒng)內(nèi)核的頁緩存中;② 應(yīng)用將數(shù)據(jù)從內(nèi)核緩存復(fù)制到應(yīng)用的緩存中;③應(yīng)用將數(shù)據(jù)寫回內(nèi)核的Socket緩存中;④操作系統(tǒng)將數(shù)據(jù)從Socket緩存區(qū)復(fù)制到網(wǎng)卡緩存,然后將其通過網(wǎng)絡(luò)發(fā)出。
  • ① 當(dāng)調(diào)用read系統(tǒng)調(diào)用時(shí),通過DMA(Direct Memory Access)將數(shù)據(jù)copy到內(nèi)核模式;② 然后由CPU控制將內(nèi)核模式數(shù)據(jù)copy到用戶模式下的 buffer中;③ read調(diào)用完成后,write調(diào)用首先將用戶模式下 buffer中的數(shù)據(jù)copy到內(nèi)核模式下的socket buffer中;④最后通過DMA copy將內(nèi)核模式下的socket buffer中的數(shù)據(jù)copy到網(wǎng)卡設(shè)備中傳送。
  • 從上面的過程可以看出,數(shù)據(jù)白白從內(nèi)核模式到用戶模式走了一圈,浪費(fèi)了兩次copy,而這兩次copy都是CPUcopy,即占用CPU資源。

磁盤IO和網(wǎng)絡(luò)IO對(duì)比

  • 首先,磁盤IO主要的延時(shí)是由(以15000rpm硬盤為例):機(jī)械轉(zhuǎn)動(dòng)延時(shí)(機(jī)械磁盤的主要性能瓶頸,平均為2ms) + 尋址延時(shí)(2~3ms) + 塊傳輸延時(shí)(一般4k每塊,40m/s的傳輸速度,延時(shí)一般為0.1ms) 決定。(平均為5ms)。
  • 而網(wǎng)絡(luò)IO主要延時(shí)是由:服務(wù)器響應(yīng)延時(shí) + 帶寬限制 + 網(wǎng)絡(luò)延時(shí) + 跳轉(zhuǎn)路由延時(shí) + 本地接收延時(shí) 決定。(一般為幾十到幾千毫秒,受環(huán)境干擾極大)。
  • 所以兩者一般來說網(wǎng)絡(luò)IO延時(shí)要大于磁盤IO的延時(shí)。

Socket網(wǎng)絡(luò)編程

客戶端

public class SocketClient {public static void main(String args[]) throws Exception {// 要連接的服務(wù)端IP地址和端口 String host = "127.0.0.1"; int port = 55533;// 與服務(wù)端建立連接Socket socket = new Socket(host, port);// 建立連接后獲得輸出流OutputStream outputStream = socket.getOutputStream(); String message="你好 yiwangzhibujian";socket.getOutputStream().write(message.getBytes("UTF-8")); outputStream.close();socket.close();} }

服務(wù)端

public class SocketServer {public static void main(String[] args) throws Exception {// 監(jiān)聽指定的端口int port = 55533;ServerSocket server = new ServerSocket(port);// server將一直等待連接的到來 System.out.println("server將一直等待連接的到來"); Socket socket = server.accept();// 建立好連接后,從socket中獲取輸入流,并建立緩沖區(qū)進(jìn)行讀取 InputStream inputStream = socket.getInputStream(); byte[] bytes = new byte[1024];int len;StringBuilder sb = new StringBuilder();while ((len = inputStream.read(bytes)) != -1) {//注意指定編碼格式,發(fā)送方和接收方一定要統(tǒng)一,建議使用UTF-8sb.append(new String(bytes, 0, len,"UTF-8"));}System.out.println("get message from client: " + sb);inputStream.close();socket.close();server.close();} } public class SocketServer {public static void main(String args[]) throws Exception {// 監(jiān)聽指定的端口int port = 55533;ServerSocket server = new ServerSocket(port); // server將一直等待連接的到來 System.out.println("server將一直等待連接的到來");//如果使用多線程,那就需要線程池,防止并發(fā)過高時(shí)創(chuàng)建過多線程耗盡資源 ExecutorService threadPool = Executors.newFixedThreadPool(100);while (true) {Socket socket = server.accept();Runnable runnable = ()->{try {// 建立好連接后,從socket中獲取輸入流,并建立緩沖區(qū)進(jìn)行讀取 InputStream inputStream = socket.getInputStream(); byte[] bytes = new byte[1024];int len;StringBuilder sb = new StringBuilder();while ((len = inputStream.read(bytes)) != -1) {// 注意指定編碼格式,發(fā)送方和接收方一定要統(tǒng)一,建議使用UTF-8sb.append(new String(bytes, 0, len, "UTF-8"));}System.out.println("get message from client: " + sb);inputStream.close();socket.close();} catch (Exception e) {e.printStackTrace();} };threadPool.submit(runnable);}} }

同步IO和異步IO

同步和異步是針對(duì)應(yīng)用程序和內(nèi)核的交互而言的,同步指的是用戶進(jìn)程觸發(fā)IO操作并等待或者輪詢的去查看IO操作是否就緒,而異步是指用戶進(jìn)程觸發(fā)IO操作以后便開始做自己的事情,而當(dāng)IO操作已經(jīng)完成的時(shí)候會(huì)得到IO完成的通知。

  • 指的是用戶空間和內(nèi)核空間數(shù)據(jù)交互的方式
  • 同步:用戶空間要的數(shù)據(jù),必須等到內(nèi)核空間給它才做其他事情。
  • 異步:用戶空間要的數(shù)據(jù),不需要等到內(nèi)核空間給它,才做其他事情。內(nèi)核空間會(huì)異步通知用戶進(jìn)程,并把數(shù)據(jù)直接給到用戶空間。

阻塞IO和非阻塞IO

阻塞方式下讀取或者寫入函數(shù)將一直等待,而非阻塞方式下,讀取或者寫入函數(shù)會(huì)立即返回一個(gè)狀態(tài)值。

  • 指的是用戶空間和內(nèi)核空間IO操作的方式
  • 阻塞:用戶空間通過系統(tǒng)調(diào)用(systemcall)和內(nèi)核空間發(fā)送IO操作時(shí),該調(diào)用是阻塞的。
  • 非阻塞:用戶空間通過系統(tǒng)調(diào)用(systemcall)和內(nèi)核空間發(fā)送IO操作時(shí),該調(diào)用是不堵塞的,直接返回的,只是返回時(shí),可能沒有數(shù)據(jù)而已。

IO設(shè)計(jì)模式之Reactor和Proactor

  • 平時(shí)接觸的開源產(chǎn)品如Redis、ACE,事件模型都使用的Reactor模式;而同樣做事件處理的Proactor,由于操作系統(tǒng)的原因,相關(guān)的開源產(chǎn)品也少。

反應(yīng)器Reactor

概述

反應(yīng)器設(shè)計(jì)模式(Reactor pattern)是一種為處理并發(fā)服務(wù)請(qǐng)求,并將請(qǐng)求提交到一個(gè)或者多個(gè)服務(wù)處理程序的事件設(shè)計(jì)模式。當(dāng)客戶端請(qǐng)求抵達(dá)后,服務(wù)處理程序使用多路分配策略,由一個(gè)非阻塞的線程來接收所有的請(qǐng)求,然后派發(fā)這些請(qǐng)求至相關(guān)的工作線程進(jìn)行處理。
Reactor模式主要包含下面幾部分內(nèi)容:

  • 初始事件分發(fā)器(Initialization Dispatcher):用于管理Event Handler,定義注冊(cè)、移除EventHandler等。它還作為Reactor模式的入口調(diào)用Synchronous Event Demultiplexer的select方法以阻塞等待事件返回,當(dāng)阻塞等待返回時(shí),根據(jù)事件發(fā)生的Handle將其分發(fā)給對(duì)應(yīng)的Event Handler處理,即回調(diào)EventHandler中的handle_event()方法。
  • 同步(多路)事件分離器(Synchronous Event Demultiplexer):無限循環(huán)等待新事件的到來,一旦發(fā)現(xiàn)有新的事件到來,就會(huì)通知初始事件分發(fā)器去調(diào)取特定的事件處理器。
  • 系統(tǒng)處理程序(Handles):操作系統(tǒng)中的句柄,是對(duì)資源在操作系統(tǒng)層面上的一種抽象,它可以是打開的文件、一個(gè)連接(Socket)、Timer等。由于Reactor模式一般使用在網(wǎng)絡(luò)編程中,因而這里一般指SocketHandle,即一個(gè)網(wǎng)絡(luò)連接(Connection,在Java NIO中的Channel)。這個(gè)Channel注冊(cè)到Synchronous Event Demultiplexer中,以監(jiān)聽Handle中發(fā)生的事件,對(duì)ServerSocketChannnel可以是CONNECT事件,對(duì) SocketChannel 可以是READ、WRITE、CLOSE事件等。
  • 事件處理器(Event Handler):定義事件處理方法,以供Initialization Dispatcher回調(diào)使用。
  • 對(duì)于Reactor模式,可以將其看做由兩部分組成,一部分是由Boss組成,另一部分是由worker組成。Boss就像老板一樣,主要是拉活兒、談項(xiàng)目,一旦Boss接到活兒了,就下發(fā)給下面的work去處理。也可以看做是項(xiàng)目經(jīng)理和程序員之間的關(guān)系。

為什么使用Reactor模式

并發(fā)系統(tǒng)常使用reactor模式代替常用的多線程的處理方式,節(jié)省系統(tǒng)的資源,提高系統(tǒng)的吞吐量。例如:在高并發(fā)的情況下,既可以使用多處理處理方式,也可以使用Reactor處理方式。

  • 多線程處理:為每個(gè)單獨(dú)到來的請(qǐng)求,專門啟動(dòng)一條線程,這樣的話造成系統(tǒng)的開銷很大,并且在單核的機(jī)上,多線程并不能提高系統(tǒng)的性能,除非在有一些阻塞的情況發(fā)生。否則線程切換的開銷會(huì)使處理的速度變慢。
  • Reactor模式處理:服務(wù)器端啟動(dòng)一條單線程,用于輪詢IO操作是否就緒,當(dāng)有就緒的才進(jìn)行相應(yīng)的讀寫操作,這樣的話就減少了服務(wù)器產(chǎn)生大量的線程,也不會(huì)出現(xiàn)線程之間的切換產(chǎn)生的性能消耗。(目前JAVA的NIO就采用的此種模式,這里引申出一個(gè)問題:在多核情況下NIO的擴(kuò)展問題)
  • 以上兩種處理方式都是基于同步的,多線程的處理是我們傳統(tǒng)模式下對(duì)高并發(fā)的處理方式,Reactor模式的處理是現(xiàn)今面對(duì)高并發(fā)和高性能一種主流的處理方式。

Reactor模式結(jié)構(gòu)


Reactor包含如下角色:

  • Handle 句柄:用來標(biāo)識(shí)socket連接或是打開文件;
  • Synchronous Event Demultiplexer:同步事件多路分解器,由操作系統(tǒng)內(nèi)核實(shí)現(xiàn)的一個(gè)函數(shù);用于阻塞等 待發(fā)生在句柄集合上的一個(gè)或多個(gè)事件(如select/epoll)。
  • Event Handler:事件處理接口。
  • Concrete Event HandlerA:實(shí)現(xiàn)應(yīng)用程序所提供的特定事件處理邏輯。
  • Reactor:反應(yīng)器,定義一個(gè)接口,實(shí)現(xiàn)以下功能
    • 供應(yīng)用程序注冊(cè)和刪除關(guān)注的事件句柄;
    • 運(yùn)行事件循環(huán)
    • 有就緒事件到來時(shí),分發(fā)事件到之前注冊(cè)的回調(diào)函數(shù)上處理。
  • Initiation Dispatcher:用于管理Event Handler,即EventHandler的容器,用以注冊(cè)、移除 EventHandler等;另外,它還作為Reactor模式的入口調(diào)用Synchronous Event Demultiplexer的select方法以阻塞等待事件返回,當(dāng)阻塞等待返回時(shí),根據(jù)事件發(fā)生的Handle將其分發(fā)給對(duì)應(yīng)的Event Handler處理, 即回調(diào)EventHandler中的handle_event()方法。

業(yè)務(wù)流程及時(shí)序圖

  • 應(yīng)用啟動(dòng),將關(guān)注的事件handle注冊(cè)到Reactor中。
  • 調(diào)用Reactor,進(jìn)入無限事件循環(huán),等待注冊(cè)的事件到來。
  • 事件到來,select返回,Reactor將事件分發(fā)到之前注冊(cè)的回調(diào)函數(shù)中處理。

Proactor模式

運(yùn)用于異步I/O操作,Proactor模式中,應(yīng)用程序不需要進(jìn)行實(shí)際的讀寫過程,它只需要從緩存區(qū)讀取或者寫入即可,操作系統(tǒng)會(huì)讀取緩存區(qū)或者寫入緩存區(qū)到真正的IO設(shè)備。
Proactor中對(duì)于寫入操作和讀取操作,只感興趣的是寫入完成事件。

Proactor模式結(jié)構(gòu)

Proactor主動(dòng)器模式包含如下角色:

  • Handle 句柄:用來標(biāo)識(shí)socket連接或是打開文件。
  • Asynchronous Operation:異步操作。
  • Asynchronous Operation Processor:異步操作處理器;負(fù)責(zé)執(zhí)行異步操作,一般由操作系統(tǒng)內(nèi)核實(shí)現(xiàn)。
  • Completion Event Queue:完成事件隊(duì)列;異步操作完成的結(jié)果放到隊(duì)列中等待后續(xù)使用。
  • Proactor:主動(dòng)器;為應(yīng)用程序進(jìn)程提供事件循環(huán);從完成事件隊(duì)列中取出異步操作的結(jié)果,分發(fā)調(diào)用相應(yīng)的后續(xù)處理邏輯。
  • Completion Handler:完成事件接口;一般是由回調(diào)函數(shù)組成的接口。
  • Concrete Completion Handler:完成事件處理邏輯;實(shí)現(xiàn)接口定義特定的應(yīng)用處理邏輯。

業(yè)務(wù)流程及時(shí)序圖

  • 應(yīng)用程序啟動(dòng),調(diào)用異步操作處理器提供的異步操作接口函數(shù),調(diào)用之后應(yīng)用程序和異步操作處理就獨(dú)立運(yùn)行;應(yīng)用程序可以調(diào)用新的異步操作,而其它操作可以并發(fā)進(jìn)行。
  • 應(yīng)用程序啟動(dòng)Proactor主動(dòng)器,進(jìn)行無限的事件循環(huán),等待完成事件到來。
  • 異步操作處理器執(zhí)行異步操作,完成后將結(jié)果放入到完成事件隊(duì)列。
  • 主動(dòng)器從完成事件隊(duì)列中取出結(jié)果,分發(fā)到相應(yīng)的完成事件回調(diào)函數(shù)處理邏輯中。

Reactor和Proactor對(duì)比

主動(dòng)和被動(dòng)

  • Reactor將handle放到select(),等待可寫就緒,然后調(diào)用write()寫入數(shù)據(jù);寫完處理后續(xù)邏輯。
  • Proactor調(diào)用aoi_write后立刻返回,由內(nèi)核負(fù)責(zé)寫操作,寫完后調(diào)用相應(yīng)的回調(diào)函數(shù)處理后續(xù)邏輯。
  • 可以看出,Reactor被動(dòng)的等待指示事件的到來并做出反應(yīng);它有一個(gè)等待的過程,做什么都要先放入到監(jiān)聽事件集合中等待handler可用時(shí)再進(jìn)行操作; Proactor直接調(diào)用異步讀寫操作,調(diào)用完后立刻返回。

實(shí)現(xiàn)

  • Reactor實(shí)現(xiàn)了一個(gè)被動(dòng)的事件分離和分發(fā)模型,服務(wù)等待請(qǐng)求事件的到來,再通過不受間斷的同步處理事件,從而做出反應(yīng)。
  • Proactor實(shí)現(xiàn)了一個(gè)主動(dòng)的事件分離和分發(fā)模型;這種設(shè)計(jì)允許多個(gè)任務(wù)并發(fā)的執(zhí)行,從而提高吞吐量;并可執(zhí)行耗時(shí)長的任務(wù)(各個(gè)任務(wù)間互不影響)。

優(yōu)點(diǎn)

  • Reactor實(shí)現(xiàn)相對(duì)簡單,對(duì)于耗時(shí)短的處理場景處理高效; 操作系統(tǒng)可以在多個(gè)事件源上等待,并且避免了多線程編程相關(guān)的性能開銷和編程復(fù)雜性; 事件的串行化對(duì)應(yīng)用是透明的,可以順序的同步執(zhí)行而不需要加鎖; 事務(wù)分離:將與應(yīng)用無關(guān)的多路分解和分配機(jī)制和與應(yīng)用相關(guān)的回調(diào)函數(shù)分離開來。
  • Proactor性能更高,能夠處理耗時(shí)長的并發(fā)場景。

缺點(diǎn)

  • Reactor處理耗時(shí)長的操作會(huì)造成事件分發(fā)的阻塞,影響到后續(xù)事件的處理。
  • Proactor實(shí)現(xiàn)邏輯復(fù)雜,依賴操作系統(tǒng)對(duì)異步的支持,目前實(shí)現(xiàn)了純異步操作的操作系統(tǒng)少,實(shí)現(xiàn)優(yōu)秀的如windows IOCP,但由于其windows系統(tǒng)用于服務(wù)器的局限性,目前應(yīng)用范圍較小;而Unix/Linux系統(tǒng)對(duì)純異步的支持有限,應(yīng)用事件驅(qū)動(dòng)的主流還是通過select/epoll來實(shí)現(xiàn)。

適用場景

  • Reactor:同時(shí)接收多個(gè)服務(wù)請(qǐng)求,并且依次同步的處理它們的事件驅(qū)動(dòng)程序。
  • Proactor:異步接收和同時(shí)處理多個(gè)服務(wù)請(qǐng)求的事件驅(qū)動(dòng)程序。

漫談五種IO模型

高性能IO模型淺析

服務(wù)器端編程經(jīng)常需要構(gòu)造高性能的IO模型,常見的IO模型有四種:

  • 同步阻塞IO(Blocking IO):即傳統(tǒng)的IO模型。
  • 同步非阻塞IO(Non-blocking IO):默認(rèn)創(chuàng)建的socket都是阻塞的,非阻塞IO要求socket被設(shè)置為NONBLOCK。注意這里所說的NIO并非Java的NIO(New IO)庫。
  • IO多路復(fù)用(IO Multiplexing):即經(jīng)典的Reactor設(shè)計(jì)模式,有時(shí)也稱為異步阻塞IO,Java中的Selector和Linux中的epoll都是這種模型。
  • 異步IO(Asynchronous IO):即經(jīng)典的Proactor設(shè)計(jì)模式,也稱為異步非阻塞IO。

IO模型舉例理解

例1

  • 阻塞IO,給女神發(fā)一條短信,說我來找你了,然后就默默的一直等著女神下樓,這個(gè)期間除了等待你不會(huì)做其他事情,屬于備胎做法。
  • 非阻塞IO,給女神發(fā)短信,如果不回,接著再發(fā),一直發(fā)到女神下樓,這個(gè)期間你除了發(fā)短信等待不會(huì)做其他事情,屬于專一做法。
  • IO多路復(fù)用,是找一個(gè)宿管大媽來幫你監(jiān)視下樓的女生,這個(gè)期間你可以些其他的事情。例如可以順便看看其他妹子,玩玩王者榮耀,上個(gè)廁所等。IO復(fù)用又包括 select、poll、epoll 模式。那么它們的區(qū)別是什么?
    • select 大媽每一個(gè)女生下樓,select大媽都不知道這個(gè)是不是你的女神,她需要一個(gè)一個(gè)詢問,并且select大媽能力還有限,最多一次幫你監(jiān)視1024個(gè)妹子。
    • poll大媽不限制盯著女生的數(shù)量,只要是經(jīng)過宿舍樓門口的女生,都會(huì)幫你去問是不是你女神。
    • epoll大媽不限制盯著女生的數(shù)量,并且也不需要一個(gè)一個(gè)去問。那么如何做呢?epoll大媽會(huì)為每個(gè)進(jìn)宿舍樓的女生臉上貼上一個(gè)大字條,上面寫上女生自己的名字,只要女生下樓了,epoll大媽就知道這個(gè)是不是你女神了,然后大媽再通知你。
  • 上面這些同步IO有一個(gè)共同點(diǎn)就是,當(dāng)女神走出宿舍門口的時(shí)候,你已經(jīng)站在宿舍門口等著女神的,此時(shí)你屬于阻塞狀態(tài)。
  • 接下來是異步IO的情況:你告訴女神我來了,然后你就去王者榮耀了,一直到女神下樓了,發(fā)現(xiàn)找不見你了,女神再給你打電話通知你,說我下樓了,你在哪呢?這時(shí)候你才來到宿舍門口。此時(shí)屬于逆襲做法。

例2

  • 阻塞I/O模型:老李去火車站買票,排隊(duì)三天買到一張退票。耗費(fèi):在車站吃喝拉撒睡 3天,其他事一件沒干。
  • 非阻塞I/O模型:老李去火車站買票,隔12小時(shí)去火車站問有沒有退票,三天后買到一張票。耗費(fèi):往返車站6次,路上6小時(shí),其他時(shí)間做了好多事。
  • I/O復(fù)用模型
    • select/poll:老李去火車站買票,委托黃牛,然后每隔6小時(shí)電話黃牛詢問,黃牛三天內(nèi)買到票,然后老李去火車站交錢領(lǐng)票。 耗費(fèi):往返車站2次,路上2小時(shí),黃牛手續(xù)費(fèi)100元,打電話17次。
    • epoll:老李去火車站買票,委托黃牛,黃牛買到后即通知老李去領(lǐng),然后老李去火車站交錢領(lǐng)票。 耗費(fèi):往返車站2次,路上2小時(shí),黃牛手續(xù)費(fèi)100元,無需打電話。
  • 信號(hào)驅(qū)動(dòng)I/O模型:老李去火車站買票,給售票員留下電話,有票后,售票員電話通知老李,然后老李去火車站交錢領(lǐng)票。 耗費(fèi):往返車站2次,路上2小時(shí),免黃牛費(fèi)100元,無需打電話。
  • 異步I/O模型:老李去火車站買票,給售票員留下電話,有票后,售票員電話通知老李并快遞送票上門。 耗費(fèi):往返車站1次,路上1小時(shí),免黃牛費(fèi)100元,無需打電話。

同步阻塞IO

  • 同步阻塞IO模型是最簡單的IO模型,用戶線程在內(nèi)核進(jìn)行IO操作時(shí)被阻塞。

  • 用戶線程通過系統(tǒng)調(diào)用read發(fā)起IO讀操作,由用戶空間轉(zhuǎn)到內(nèi)核空間。內(nèi)核等到數(shù)據(jù)包到達(dá)后,然后將接收的數(shù)據(jù)拷貝到用戶空間,完成read操作。
  • 用戶線程使用同步阻塞IO模型的偽代碼描述為:
{read(socket, buffer);process(buffer); }
  • 即用戶需要等待read將socket中的數(shù)據(jù)讀取到buffer后,才繼續(xù)處理接收的數(shù)據(jù)。整個(gè)IO請(qǐng)求的過程中,用戶線程是被阻塞的,這導(dǎo)致用戶在發(fā)起IO請(qǐng)求時(shí),不能做任何事情,對(duì)CPU的資源利用率不夠。

同步非阻塞IO

  • 同步非阻塞IO是在同步阻塞IO的基礎(chǔ)上,將socket設(shè)置為NONBLOCK。這樣做用戶線程可以在發(fā)起IO請(qǐng)求后可以立即返回。

  • 由于socket是非阻塞的方式,因此用戶線程發(fā)起IO請(qǐng)求時(shí)立即返回。但并未讀取到任何數(shù)據(jù),用戶線程需要不斷地發(fā)起IO請(qǐng)求,直到數(shù)據(jù)到達(dá)后,才真正讀取到數(shù)據(jù),繼續(xù)執(zhí)行。
  • 用戶線程使用同步非阻塞IO模型的偽代碼描述為:
{while(read(socket, buffer) != SUCCESS);process(buffer); }

IO多路復(fù)用

  • IO多路復(fù)用模型是建立在內(nèi)核提供的多路分離函數(shù)select基礎(chǔ)之上的,使用select函數(shù)可以避免同步非阻塞IO模型中輪詢等待的問題。

  • 用戶首先將需要進(jìn)行IO操作的socket添加到select中,然后阻塞等待select系統(tǒng)調(diào)用返回。當(dāng)數(shù)據(jù)到達(dá)時(shí),socket被激活,select函數(shù)返回。用戶線程正式發(fā)起read請(qǐng)求,讀取數(shù)據(jù)并繼續(xù)執(zhí)行。
  • 從流程上來看,使用select函數(shù)進(jìn)行IO請(qǐng)求和同步阻塞模型沒有太大的區(qū)別,甚至還多了添加監(jiān)視socket,以及調(diào)用select函數(shù)的額外操作,效率更差。但是,使用select以后最大的優(yōu)勢是用戶可以在一個(gè)線程內(nèi)同時(shí)處理多個(gè)socket的IO請(qǐng)求。用戶可以注冊(cè)多個(gè)socket,然后不斷地調(diào)用select讀取被激活的socket,即可達(dá)到在同一個(gè)線程內(nèi)同時(shí)處理多個(gè)IO請(qǐng)求的目的。而在同步阻塞模型中,必須通過多線程的方式才能達(dá)到這個(gè)目的。
  • 用戶線程使用select函數(shù)的偽代碼描述為:
{select(socket);while(1) {sockets = select();for(socket in sockets) {if(can_read(socket)) {read(socket, buffer);process(buffer);}}} }
  • 其中while循環(huán)前將socket添加到select監(jiān)視中,然后在while內(nèi)一直調(diào)用select獲取被激活的socket,一旦socket可讀,便調(diào)用read函數(shù)將socket中的數(shù)據(jù)讀取出來。
  • 然而,使用select函數(shù)的優(yōu)點(diǎn)并不僅限于此。雖然上述方式允許單線程內(nèi)處理多個(gè)IO請(qǐng)求,但是每個(gè)IO請(qǐng)求的過程還是阻塞的(在select函數(shù)上阻塞),平均時(shí)間甚至比同步阻塞IO模型還要長。
  • 如果用戶線程只注冊(cè)自己感興趣的socket或者IO請(qǐng)求,然后去做自己的事情,等到數(shù)據(jù)到來時(shí)再進(jìn)行處理,則可以提高CPU的利用率。
  • IO多路復(fù)用模型使用了Reactor設(shè)計(jì)模式實(shí)現(xiàn)了這一機(jī)制。

  • 通過Reactor的方式,可以將用戶線程輪詢IO操作狀態(tài)的工作統(tǒng)一交給handle_events事件循環(huán)進(jìn)行處理。用戶線程注冊(cè)事件處理器之后可以繼續(xù)執(zhí)行做其他的工作(異步),而Reactor線程負(fù)責(zé)調(diào)用內(nèi)核的select函數(shù)檢查socket狀態(tài)。當(dāng)有socket被激活時(shí),則通知相應(yīng)的用戶線程(或執(zhí)行用戶線程的回調(diào)函數(shù)),執(zhí)行handle_event進(jìn)行數(shù)據(jù)讀取、處理的工作。由于select函數(shù)是阻塞的,因此多路IO復(fù)用模型也被稱為異步阻塞IO模型。注意,這里的所說的阻塞是指select函數(shù)執(zhí)行時(shí)線程被阻塞,而不是指socket。一般在使用IO多路復(fù)用模型時(shí),socket都是設(shè)置為NONBLOCK的,不過這并不會(huì)產(chǎn)生影響,因?yàn)橛脩舭l(fā)起IO請(qǐng)求時(shí),數(shù)據(jù)已經(jīng)到達(dá)了,用戶線程一定不會(huì)被阻塞。
  • 用戶線程使用IO多路復(fù)用模型的偽代碼描述為:
void UserEventHandler::handle_event() {if(can_read(socket)) {read(socket, buffer);process(buffer);} } {Reactor.register(new UserEventHandler(socket)); }
  • 用戶需要重寫EventHandler的handle_event函數(shù)進(jìn)行讀取數(shù)據(jù)、處理數(shù)據(jù)的工作,用戶線程只需要將自己的EventHandler注冊(cè)到Reactor即可。Reactor中handle_events事件循環(huán)的偽代碼大致如下。
Reactor::handle_events() {while(1) {sockets = select();for(socket in sockets) {get_event_handler(socket).handle_event();}} }
  • 事件循環(huán)不斷地調(diào)用select獲取被激活的socket,然后根據(jù)獲取socket對(duì)應(yīng)的EventHandler,執(zhí)行器handle_event函數(shù)即可。
  • IO多路復(fù)用是最常使用的IO模型,但是其異步程度還不夠“徹底”,因?yàn)樗褂昧藭?huì)阻塞線程的select系統(tǒng)調(diào)用。因此IO多路復(fù)用只能稱為異步阻塞IO,而非真正的異步IO。

異步IO

  • “真正”的異步IO需要操作系統(tǒng)更強(qiáng)的支持。在IO多路復(fù)用模型中,事件循環(huán)將文件句柄的狀態(tài)事件通知給用戶線程,由用戶線程自行讀取數(shù)據(jù)、處理數(shù)據(jù)。而在異步IO模型中,當(dāng)用戶線程收到通知時(shí),數(shù)據(jù)已經(jīng)被內(nèi)核讀取完畢,并放在了用戶線程指定的緩沖區(qū)內(nèi),內(nèi)核在IO完成后通知用戶線程直接使用即可。
  • 異步IO模型使用了Proactor設(shè)計(jì)模式實(shí)現(xiàn)了這一機(jī)制

  • 異步IO模型中,用戶線程直接使用內(nèi)核提供的異步IO API發(fā)起read請(qǐng)求,且發(fā)起后立即返回,繼續(xù)執(zhí)行用戶線程代碼。不過此時(shí)用戶線程已經(jīng)將調(diào)用的AsynchronousOperation和CompletionHandler注冊(cè)到內(nèi)核,然后操作系統(tǒng)開啟獨(dú)立的內(nèi)核線程去處理IO操作。當(dāng)read請(qǐng)求的數(shù)據(jù)到達(dá)時(shí),由內(nèi)核負(fù)責(zé)讀取socket中的數(shù)據(jù),并寫入用戶指定的緩沖區(qū)中。最后內(nèi)核將read的數(shù)據(jù)和用戶線程注冊(cè)的CompletionHandler分發(fā)給內(nèi)部Proactor,Proactor將IO完成的信息通知給用戶線程(一般通過調(diào)用用戶線程注冊(cè)的完成事件處理函數(shù)),完成異步IO。
  • 用戶線程使用異步IO模型的偽代碼描述為:
void UserCompletionHandler::handle_event(buffer) {process(buffer); } {aio_read(socket, new UserCompletionHandler); }
  • 用戶需要重寫CompletionHandler的handle_event函數(shù)進(jìn)行處理數(shù)據(jù)的工作,參數(shù)buffer表示Proactor已經(jīng)準(zhǔn)備好的數(shù)據(jù),用戶線程直接調(diào)用內(nèi)核提供的異步IO API,并將重寫的CompletionHandler注冊(cè)即可。
  • 相比于IO多路復(fù)用模型,異步IO并不十分常用,不少高性能并發(fā)服務(wù)程序使用IO多路復(fù)用模型+多線程任務(wù)處理的架構(gòu)基本可以滿足需求。況且目前操作系統(tǒng)對(duì)異步IO的支持并非特別完善,更多的是采用IO多路復(fù)用模型模擬異步IO的方式(IO事件觸發(fā)時(shí)不直接通知用戶線程,而是將數(shù)據(jù)讀寫完畢后放到用戶指定的緩沖區(qū)中)。

Redis的IO多路復(fù)用技術(shù)

redis 是一個(gè)單線程卻性能非常好的內(nèi)存數(shù)據(jù)庫, 主要用來作為緩存系統(tǒng)。 redis 采用網(wǎng)絡(luò)IO多路復(fù)用技術(shù)來保證在多連接的時(shí)候, 系統(tǒng)的高吞吐量。

為什么Redis中要使用I/O多路復(fù)用

  • 首先,Redis 是跑在單線程中的,所有的操作都是按照順序線性執(zhí)行的,但是由于讀寫操作等待用戶輸入或輸出都是阻塞的,所以 I/O 操作在一般情況下往往不能直接返回,這會(huì)導(dǎo)致某一文件的 I/O 阻塞導(dǎo)致整個(gè)進(jìn)程無法對(duì)其它客戶提供服務(wù),而 I/O 多路復(fù)用就是為了解決這個(gè)問題而出現(xiàn)的。
  • select,poll,epoll都是IO多路復(fù)用的機(jī)制。I/O多路復(fù)用就通過一種機(jī)制,可以監(jiān)視多個(gè)描述符,一旦某個(gè)描述符就緒,能夠通知程序進(jìn)行相應(yīng)的操作。
  • redis的io模型主要是基于epoll實(shí)現(xiàn)的,不過它也提供了 select和kqueue的實(shí)現(xiàn),默認(rèn)采用epoll

epoll實(shí)現(xiàn)機(jī)制

設(shè)想一下如下場景:有100萬個(gè)客戶端同時(shí)與一個(gè)服務(wù)器進(jìn)程保持著TCP連接。而每一時(shí)刻,通常只有幾百上千個(gè)TCP連接是活躍的(事實(shí)上大部分場景都是這種情況)。如何實(shí)現(xiàn)這樣的高并發(fā)?

  • 在select/poll時(shí)代,服務(wù)器進(jìn)程每次都把這100萬個(gè)連接告訴操作系統(tǒng)(從用戶態(tài)復(fù)制句柄數(shù)據(jù)結(jié)構(gòu)到內(nèi)核態(tài)),讓操作系統(tǒng)內(nèi)核去查詢這些套接字上是否有事件發(fā)生,輪詢完后,再將句柄數(shù)據(jù)復(fù)制到用戶態(tài),讓服務(wù)器應(yīng)用程序輪詢處理已發(fā)生的網(wǎng)絡(luò)事件,這一過程資源消耗較大,因此,select/poll一般只能處理幾千的并發(fā)連接。
  • 如果沒有I/O事件產(chǎn)生,我們的程序就會(huì)阻塞在select處。但是依然有個(gè)問題,我們從select那里僅僅知道了,有I/O事件發(fā)生了,但卻并不知道是那幾個(gè)流(可能有一個(gè),多個(gè),甚至全部),我們只能 所有流,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流,對(duì)他們進(jìn)行操作。
  • 但是使用select,我們有O(n)的無差別輪詢復(fù)雜度,同時(shí)處理的流越多,每一次無差別輪詢時(shí)間就越長。
  • 總結(jié):select 和 poll 的缺點(diǎn)如下:
    • 每次調(diào)用select/poll,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài),這個(gè)開銷在fd很多時(shí)會(huì)很大。
    • 同時(shí)每次調(diào)用select/poll都需要在內(nèi)核遍歷傳遞進(jìn)來的所有fd,這個(gè)開銷在fd很多時(shí)也很大。
    • 針對(duì)select支持的文件描述符數(shù)量太小了,默認(rèn)是1024。
    • select返回的是含有整個(gè)句柄的數(shù)組,應(yīng)用程序需要遍歷整個(gè)數(shù)組才能發(fā)現(xiàn)哪些句柄發(fā)生了事件。
    • select的觸發(fā)方式是水平觸發(fā),應(yīng)用程序如果沒有完成對(duì)一個(gè)已經(jīng)就緒的文件描述符進(jìn)行IO操作,那么之后每次select調(diào)用還是會(huì)將這些文件描述符通知進(jìn)程。
    • 相比select模型,poll使用鏈表保存文件描述符,因此沒有了監(jiān)視文件數(shù)量的限制,但其他三個(gè)缺點(diǎn)依然存在。
  • epoll的設(shè)計(jì)和實(shí)現(xiàn)與select完全不同。epoll是poll的一種優(yōu)化,返回后不需要對(duì)所有的fd進(jìn)行遍歷,在內(nèi)核中維持了fd的列表。select和poll是將這個(gè)內(nèi)核列表維持在用戶態(tài),然后傳遞到內(nèi)核中。與poll/select不同,epoll不再是一個(gè)單獨(dú)的系統(tǒng)調(diào)用,而是由epoll_create、epoll_ctl、epoll_wait三個(gè)系統(tǒng)調(diào)用組成。
  • epoll在2.6以后的內(nèi)核才支持。
  • epoll通過在Linux內(nèi)核中申請(qǐng)一個(gè)簡易的文件系統(tǒng)(文件系統(tǒng)一般用什么數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)?B+樹)。把原先的select/poll調(diào)用分成了3個(gè)部分:
    • 調(diào)用epoll_create()建立一個(gè)epoll對(duì)象(在epoll文件系統(tǒng)中為這個(gè)句柄對(duì)象分配資源)。
    • 調(diào)用epoll_ctl向epoll對(duì)象中添加這100萬個(gè)連接的套接字。
    • 調(diào)用epoll_wait收集發(fā)生的事件的連接。
  • 如此一來,要實(shí)現(xiàn)上面說是的場景,只需要在進(jìn)程啟動(dòng)時(shí)建立一個(gè)epoll對(duì)象,然后在需要的時(shí)候向這個(gè)epoll對(duì)象中添加或者刪除連接。同時(shí),epoll_wait的效率也非常高,因?yàn)檎{(diào)用epoll_wait時(shí),并沒有一股腦的向操作系統(tǒng)復(fù)制這100萬個(gè)連接的句柄數(shù)據(jù),內(nèi)核也不需要去遍歷全部的連接。
  • 總結(jié)epoll優(yōu)點(diǎn):
    • epoll 沒有最大并發(fā)連接的限制,上限是最大可以打開文件的數(shù)目,這個(gè)數(shù)字一般遠(yuǎn)大于 2048, 一般來說這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大 ,具體數(shù)目可以 cat /proc/sys/fs/file-max 察看。
    • 效率提升, epoll 最大的優(yōu)點(diǎn)就在于它只管你“活躍”的連接 ,而跟連接總數(shù)無關(guān),因此在實(shí)際的網(wǎng)絡(luò)環(huán)境中, epoll 的效率就會(huì)遠(yuǎn)遠(yuǎn)高于 select 和 poll 。
    • 內(nèi)存拷貝, epoll 在這點(diǎn)上使用了“共享內(nèi)存”,這個(gè)內(nèi)存拷貝也省略了。

redis epoll底層實(shí)現(xiàn)

  • 當(dāng)某一進(jìn)程調(diào)用epoll_create方法時(shí),Linux內(nèi)核會(huì)創(chuàng)建一個(gè)eventpoll結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體中有兩個(gè)成員與epoll的使用方式密切相關(guān)。
  • eventpoll結(jié)構(gòu)體如下所示:
struct eventpoll {/*紅黑樹的根結(jié)點(diǎn),這顆樹中存儲(chǔ)著所有添加到epoll中的需要監(jiān)控的事件*/struct rb_root rbr;/*雙鏈表中存放著將要通過epoll_wait返回給用戶的滿足條件的事件*/struct list_head rdlist; }
  • 每一個(gè)epoll對(duì)象都有一個(gè)獨(dú)立的eventpoll結(jié)構(gòu)體,用于存放通過epoll_ctl方法向epoll對(duì)象中添加進(jìn)來的事件。這些事件都會(huì)掛載在紅黑樹中,如此,重復(fù)添加的事件就可以通過紅黑樹而高效的識(shí)別出來(紅黑樹的插入時(shí)間效率是lgn,其中n為樹的高度)。
  • 而所有添加到epoll中的事件都會(huì)與設(shè)備(網(wǎng)卡)驅(qū)動(dòng)程序建立回調(diào)關(guān)系,也就是說,當(dāng)相應(yīng)的事件發(fā)生時(shí)會(huì)調(diào)用這個(gè)回調(diào)方法。這個(gè)回調(diào)方法在內(nèi)核中叫ep_poll_callback,它會(huì)將發(fā)生的事件添加到rdlist雙鏈表中。
  • 在epoll中,對(duì)于每一個(gè)事件,都會(huì)建立一個(gè)epitem結(jié)構(gòu)體,如下所示:
struct epitem {struct rb_node rbn; // 紅黑樹節(jié)點(diǎn)struct list_head rdllink; // 雙向鏈表節(jié)點(diǎn)struct epoll_filefd ffd; // 事件句柄信息struct eventpoll *ep; // 指向其所屬的eventpoll對(duì)象struct epoll_event event; // 期待發(fā)生的事件類型 }
  • 當(dāng)調(diào)用epoll_wait檢查是否有事件發(fā)生時(shí),只需要檢查eventpoll對(duì)象中的rdlist雙鏈表中是否有epitem元素即可。如果rdlist不為空,則把發(fā)生的事件復(fù)制到用戶態(tài),同時(shí)將事件數(shù)量返回給用戶。

  • 優(yōu)勢:

    • 不用重復(fù)傳遞:我們調(diào)用epoll_wait時(shí)就相當(dāng)于以往調(diào)用select/poll,但是這時(shí)卻不用傳遞socket句柄給內(nèi)核,因?yàn)閮?nèi)核已經(jīng)在epoll_ctl中拿到了要監(jiān)控的句柄列表。
    • 在內(nèi)核里,一切皆文件:所以,epoll向內(nèi)核注冊(cè)了一個(gè)文件系統(tǒng),用于存儲(chǔ)上述的被監(jiān)控socket。當(dāng)你調(diào)用epoll_create時(shí),就會(huì)在這個(gè)虛擬的epoll文件系統(tǒng)里創(chuàng)建一個(gè)file結(jié)點(diǎn)。當(dāng)然這個(gè)file不是普通文件,它只服務(wù)于epoll。epoll在被內(nèi)核初始化時(shí)(操作系統(tǒng)啟動(dòng)),同時(shí)會(huì)開辟出epoll自己的內(nèi)核高速cache區(qū),用于安置每一個(gè)我們想監(jiān)控的socket,這些socket會(huì)以紅黑樹的形式保存在內(nèi)核cache里,以支持快速的查找、插入、刪除。這個(gè)內(nèi)核高速cache區(qū),就是建立連續(xù)的物理內(nèi)存頁,然后在之上建立slab層,簡單的說,就是物理上分配好你想要的size的內(nèi)存對(duì)象,每次使用時(shí)都是使用空閑的已分配好的對(duì)象。
    • 極其高效的原因:這是由于我們?cè)谡{(diào)用epoll_create時(shí),內(nèi)核除了幫我們?cè)趀poll文件系統(tǒng)里建了個(gè)file結(jié)點(diǎn),在內(nèi)核cache里建了個(gè)紅黑樹用于存儲(chǔ)以后epoll_ctl傳來的socket外,還會(huì)再建立一個(gè)list鏈表,用于存儲(chǔ)準(zhǔn)備就緒的事件,當(dāng)epoll_wait調(diào)用時(shí),僅僅觀察這個(gè)list鏈表里有沒有數(shù)據(jù)即可。有數(shù)據(jù)就返回,沒有數(shù)據(jù)就sleep,等到timeout時(shí)間到后即使鏈表沒數(shù)據(jù)也返回。所以,epoll_wait非常高效。
  • 這個(gè)準(zhǔn)備就緒list鏈表是怎么維護(hù)的呢?

    • 當(dāng)我們執(zhí)行epoll_ctl時(shí),除了把socket放到epoll文件系統(tǒng)里file對(duì)象對(duì)應(yīng)的紅黑樹上之外,還會(huì)給內(nèi)核中斷處理程序注冊(cè)一個(gè)回調(diào)函數(shù),告訴內(nèi)核,如果這個(gè)句柄的中斷到了,就把它放到準(zhǔn)備就緒list鏈表里。所以,當(dāng)一個(gè)socket上有數(shù)據(jù)到了,內(nèi)核在把網(wǎng)卡上的數(shù)據(jù)copy到內(nèi)核中后就來把socket插入到準(zhǔn)備就緒鏈表里了。(注:好好理解這句話!)
    • 從上面這句可以看出,epoll的基礎(chǔ)就是回調(diào)呀!
  • 如此,一顆紅黑樹,一張準(zhǔn)備就緒句柄鏈表,少量的內(nèi)核cache,就幫我們解決了大并發(fā)下的socket處理問題。執(zhí)行epoll_create時(shí),創(chuàng)建了紅黑樹和就緒鏈表,執(zhí)行epoll_ctl時(shí),如果增加socket句柄,則檢查在紅黑樹中是否存在,存在立即返回,不存在則添加到樹干上,然后向內(nèi)核注冊(cè)回調(diào)函數(shù),用于當(dāng)中斷事件來臨時(shí)向準(zhǔn)備就緒鏈表中插入數(shù)據(jù)。執(zhí)行epoll_wait時(shí)立刻返回準(zhǔn)備就緒鏈表里的數(shù)據(jù)即可。

  • 最后看看epoll獨(dú)有的兩種模式LT和ET。無論是LT和ET模式,都適用于以上所說的流程。區(qū)別是,LT模式下,只要一個(gè)句柄上的事件一次沒有處理完,會(huì)在以后調(diào)用epoll_wait時(shí)次次返回這個(gè)句柄,而ET模式僅在第一次返回。

  • 關(guān)于LT,ET,有一端描述,LT和ET都是電子里面的術(shù)語,ET是邊緣觸發(fā),LT是水平觸發(fā),一個(gè)表示只有在變化的邊際觸發(fā),一個(gè)表示在某個(gè)階段都會(huì)觸發(fā)。

  • LT, ET這件事怎么做到的呢?當(dāng)一個(gè)socket句柄上有事件時(shí),內(nèi)核會(huì)把該句柄插入上面所說的準(zhǔn)備就緒list鏈表,這時(shí)我們調(diào)用epoll_wait,會(huì)把準(zhǔn)備就緒的socket拷貝到用戶態(tài)內(nèi)存,然后清空準(zhǔn)備就緒list鏈表,最后,epoll_wait干了件事,就是檢查這些socket,如果不是ET模式(就是LT模式的句柄了),并且這些socket上確實(shí)有未處理的事件時(shí),又把該句柄放回到剛剛清空的準(zhǔn)備就緒鏈表了。所以,非ET的句柄,只要它上面還有事件,epoll_wait每次都會(huì)返回這個(gè)句柄。(從上面這段,可以看出,LT還有個(gè)回放的過程,低效了)

總結(jié)

以上是生活随笔為你收集整理的IO模型、IO多路复用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

免费成人在线视频网站 | 中文字幕亚洲国产 | 亚洲精品美女久久久久网站 | 免费一级特黄录像 | 欧美男女爱爱视频 | 精品久久一区二区三区 | 91网在线 | 色在线免费视频 | 又黄又刺激视频 | 啪啪免费试看 | 在线观看黄网站 | 欧美另类美少妇69xxxx | 日日爽视频 | 99在线精品观看 | 91亚洲成人 | 婷婷亚洲最大 | 精品久久久久久亚洲 | 国产裸体视频bbbbb | 中日韩三级视频 | 久久免费黄色网址 | 国产成人精品午夜在线播放 | 色婷婷综合久久久 | 欧美亚洲一区二区在线 | 天天操天天操天天操天天操 | 久久久精品国产一区二区三区 | 国产电影一区二区三区四区 | 91麻豆精品国产午夜天堂 | 色天天 | 天天爱天天插 | 亚洲精品在线观看网站 | 美女网站在线观看 | 亚洲永久字幕 | 91社区国产高清 | 精品久久网 | 亚洲免费资源 | 亚洲国产成人av网 | 色视频一区 | 国产精品婷婷午夜在线观看 | 国产999精品视频 | 就色干综合 | 久久激情视频 久久 | 99久久日韩精品视频免费在线观看 | 五月花激情| 日韩免费在线观看视频 | 夜夜躁狠狠躁 | 在线视频18在线视频4k | 国产中文字幕三区 | 中文字幕二区三区 | 麻豆传媒一区二区 | 免费在线观看一区二区三区 | 午夜私人影院久久久久 | 激情久久影院 | 在线观看国产 | 免费色视频 | 国产成人精品一区二区三区 | 江苏妇搡bbbb搡bbbb | 亚洲色图美腿丝袜 | 在线激情影院一区 | 国产麻豆剧传媒免费观看 | 欧美大香线蕉线伊人久久 | 天天插天天狠 | 亚洲精品高清一区二区三区四区 | 亚洲精品美女免费 | 国产精品自产拍在线观看中文 | 国产成人亚洲在线观看 | 国产精品成人自产拍在线观看 | 亚洲精品免费在线 | 久久综合九色 | 日本性高潮视频 | 精品人人人| 亚洲精品白浆高清久久久久久 | 亚洲精品视频免费观看 | 国产精品黄色 | 久久极品 | 五月天激情综合 | 18做爰免费视频网站 | 国产女教师精品久久av | 日韩欧美一区二区三区视频 | 奇米影视777四色米奇影院 | 久久超级碰 | 国产成人久久av | 久久视频这里只有精品 | 99久久99久国产黄毛片 | 精品999在线观看 | 91桃色在线观看视频 | 97福利在线| 成人欧美一区二区三区黑人麻豆 | a久久免费视频 | 一区二区三区在线视频111 | 成人在线黄色电影 | 成年人免费av网站 | 最近高清中文在线字幕在线观看 | 欧美性色综合 | 中文字幕影片免费在线观看 | 在线 国产一区 | 在线观看亚洲精品视频 | 97在线视频网站 | 最近中文字幕国语免费av | 日日狠狠| 亚洲电影图片小说 | 成人永久在线 | 亚洲精品美女在线观看播放 | 欧美精品天堂 | 五月天九九 | 精品国产免费观看 | 亚洲一区日韩 | 色永久免费视频 | 亚洲免费色| 久久99国产精品 | 国产一区二区精品久久 | 操操操人人 | 欧美午夜视频在线 | www.黄色网.com| 国产成人一区二区三区免费看 | 国产在线观看免费av | 综合激情av| 91精品久久久久久久久 | 亚洲经典在线 | 国产精品99久久久 | 国产精品第7页 | 337p日本欧洲亚洲大胆裸体艺术 | 久久综合精品国产一区二区三区 | 国产精品免费观看国产网曝瓜 | 一级α片免费看 | 国产小视频免费在线网址 | 国产在线看一区 | 中文字幕国产一区 | 91精品在线视频观看 | 日批视频在线 | 黄色成人在线观看 | 欧美一二三区播放 | 欧美一级片免费在线观看 | 成年人在线免费看视频 | 精品999在线观看 | www91在线| 欧美日韩国产在线 | 97在线免费观看视频 | avcom在线 | 超碰免费97 | 久久久久国产视频 | 美女视频久久 | 91免费看黄色 | 亚洲欧美视频在线观看 | 国产 日韩 在线 亚洲 字幕 中文 | 一区二区三区日韩在线 | 国产最新网站 | 日韩精品一区在线播放 | 亚洲精品女人久久久 | 97成人精品视频在线播放 | 国产一区电影在线观看 | 欧美日韩免费观看一区二区三区 | 日夜夜精品视频 | 国产不卡视频 | 欧美亚洲一区二区在线 | 色婷婷狠狠五月综合天色拍 | 97超视频 | 九九热在线观看视频 | 久久国产欧美日韩精品 | 国产一区二区三区免费在线 | 一本大道久久精品懂色aⅴ 五月婷社区 | 亚洲欧美日本一区二区三区 | 麻豆高清免费国产一区 | 国产一级黄 | 日韩视频免费观看高清 | 九九色网 | 欧美动漫一区二区三区 | 亚洲天堂网在线视频观看 | 久久三级毛片 | 久久系列| 日本aaaa级毛片在线看 | 国产无区一区二区三麻豆 | 亚洲一二三在线 | 国产一卡在线 | 中国一级片在线播放 | 伊人资源视频在线 | 欧美日韩国产页 | 日本精品在线 | 成人在线观看资源 | 久久乐九色婷婷综合色狠狠182 | 国产成人三级三级三级97 | 在线激情小视频 | 日韩中文在线播放 | 天天综合精品 | 天天干人人插 | 97精品国产91久久久久久久 | 成人 亚洲 欧美 | 精品久久久久免费极品大片 | 日韩精品免费一区二区三区 | 欧美一级专区免费大片 | 九九免费在线看完整版 | 亚洲精品自在在线观看 | 欧美日韩在线观看一区 | 亚洲精品小视频 | 91亚洲网 | 久久视影 | 人人舔人人射 | 欧美国产视频在线 | 99热这里只有精品久久 | 国产精品短视频 | 91在线免费播放视频 | 91精品中文字幕 | 亚洲综合在线发布 | 91亚洲精品久久久蜜桃网站 | 一区中文字幕 | 中文在线√天堂 | 天天干天天干天天色 | 久久dvd | 国产精品久久久久久久av电影 | av在线精品 | 玖玖玖在线观看 | 欧美日韩高清一区二区 国产亚洲免费看 | 日韩精品中文字幕av | 精品欧美一区二区三区久久久 | 免费看污片 | 免费国产亚洲视频 | 国产亚洲精品女人久久久久久 | 欧美国产精品一区二区 | 亚洲夜夜综合 | 久久另类小说 | 91最新国产| 91高清完整版在线观看 | 国产三级在线播放 | 中文字幕亚洲欧美日韩2019 | 悠悠av资源片 | 亚洲精品午夜视频 | 99热九九这里只有精品10 | www色综合 | 国产精品黑丝在线观看 | 成人在线网站观看 | 人人添人人澡人人澡人人人爽 | 五月天.com| 五月天丁香视频 | 国产最新福利 | 最新av电影网站 | 91精品视屏 | 国产永久免费观看 | 一区二区三区国 | 欧美日bb | 99精品免费久久久久久久久 | 天天操天天摸天天爽 | 欧美日韩国产高清视频 | 成年人国产在线观看 | av中文天堂在线 | 久久人人爽人人爽人人片 | 一区二区三区中文字幕在线 | 欧美精品做受xxx性少妇 | 国产自产在线视频 | 亚洲国产成人在线 | 91精品国产三级a在线观看 | 四虎国产精品免费观看视频优播 | 国产精品久久久久久婷婷天堂 | 婷婷亚洲五月 | 日本xxxx.com | 蜜臀久久99精品久久久久久网站 | 五月天狠狠操 | 最新国产在线观看 | 国产精品99久久99久久久二8 | 亚洲国产99 | 成人在线免费av | 五月天六月婷婷 | 欧美日韩xx | 欧美日韩超碰 | 久久婷亚洲五月一区天天躁 | 丁香六月五月婷婷 | 粉嫩av一区二区三区免费 | 国产中文字幕一区二区 | 久草电影免费在线观看 | 国产伦精品一区二区三区在线 | 爱色av.com | 一区二区三区四区在线 | 婷婷精品国产一区二区三区日韩 | 青青色影院 | 人人澡人人添人人爽一区二区 | 一区二区中文字幕在线 | 99在线热播精品免费 | 中文字幕在线观看av | 国产亚洲精品久久网站 | 69国产盗摄一区二区三区五区 | 黄色片免费电影 | 国产成人99av超碰超爽 | 亚洲精品在 | 成人国产综合 | 欧美精品一区二区免费 | 久久99精品国产91久久来源 | 国产精品正在播放 | 91在线精品视频 | 射射射av| 日韩 国产 | 欧美一区二区三区激情视频 | 日日操天天爽 | 四虎精品成人免费网站 | 青草草在线视频 | 亚洲第二色 | 国产 成人 久久 | 久草视频在 | 日本中文字幕高清 | 欧美激情第八页 | 国产免费二区 | 九九免费在线看完整版 | 天天在线免费视频 | 99久在线精品99re8热视频 | 天堂资源在线观看视频 | 国产精品久久毛片 | 激情网在线观看 | www亚洲一区 | 日韩av有码在线 | 91视频观看免费 | 亚洲91中文字幕无线码三区 | 99av国产精品欲麻豆 | 日韩久久片 | 中文字幕日韩在线播放 | 日韩精品一区二区不卡 | 欧美激情精品久久久久 | 一区二区三区精品在线 | 天天操狠狠操网站 | 精品国产一区二区三区日日嗨 | 免费视频国产 | 国产免费资源 | 日韩电影一区二区三区 | 欧美日韩国产在线 | 美女一级毛片视频 | 网站免费黄色 | 欧美性黄网官网 | 日韩资源在线播放 | aaawww| 婷婷亚洲五月色综合 | 久久这里只有精品1 | 国产美女久久久 | 免费观看成人 | 免费黄a大片 | 久草在线观看视频免费 | 成人国产精品免费观看 | 在线观看视频你懂 | 久草视频免费在线播放 | 国产精品一区二区三区免费视频 | 日日干,天天干 | 欧美激情视频在线观看免费 | 精品中文字幕在线播放 | 久久蜜臀av | 波多野结衣一区三区 | 成年人免费电影在线观看 | 久久视频免费 | 国产精品永久在线 | 91在线最新 | 波多野结衣在线视频免费观看 | 国产精品一区二区av日韩在线 | 7777xxxx| 国产特级毛片aaaaaa毛片 | 欧美一区二区三区在线观看 | 在线国产能看的 | 97成人在线 | 日韩免费看视频 | 91成人看片 | 亚洲激情综合 | 色视频在线观看免费 | 特黄一级毛片 | 亚洲国产中文字幕在线 | 亚洲最快最全在线视频 | 国产一级不卡视频 | 国模一区二区三区四区 | 国产免费久久精品 | 九九热免费在线观看 | 97av超碰| 在线观看亚洲国产 | 色六月婷婷| 午夜色性片 | 日韩综合一区二区 | 日韩中文字幕视频在线观看 | 亚洲精品高清视频在线观看 | 久久国语露脸国产精品电影 | 天堂av在线7| av电影免费看 | 成人动漫视频在线 | 亚洲欧美日韩国产一区二区三区 | 久久久久久久免费看 | 日韩av线观看 | av网站在线免费观看 | 免费成人在线观看 | 中文字幕黄网 | 97成人精品视频在线观看 | 国产精品久久伊人 | 一区二区三区四区在线免费观看 | 婷婷精品在线视频 | 欧美日韩在线电影 | 久操视频在线免费看 | 草久草久 | 91成版人在线观看入口 | 日韩欧美精品在线观看视频 | 天堂在线v | 久免费视频 | 国产一区二区成人 | 91激情视频在线 | 日韩videos高潮hd | 国产精品毛片完整版 | 99热手机在线观看 | 国产精品1区2区在线观看 | 亚洲视频专区在线 | 中文字幕人成乱码在线观看 | 99久久日韩精品视频免费在线观看 | 日韩伦理片一区二区三区 | 国产在线欧美日韩 | 最新国产一区二区三区 | 香蕉视频久久 | 国产97色| 99久久精品国产欧美主题曲 | av成人在线电影 | 成人avav | 国产一在线精品一区在线观看 | 日韩电影一区二区三区 | 射久久 | 成人资源网 | 干干夜夜 | 香蕉久久国产 | 免费视频资源 | 欧美动漫一区二区三区 | 久久新视频 | 久久久午夜视频 | 国产99视频在线观看 | 日韩精品免费一区二区 | 久久国产精品区 | 成人av电影免费 | 国产在线观看黄 | 欧美一级性生活片 | 久久久国产精品久久久 | 91成人网在线播放 | 又黄又刺激视频 | 成人午夜在线观看 | 狠狠狠色丁香婷婷综合激情 | 色姑娘综合天天 | 国产精品9区 | 国产亚洲精品久久久久久大师 | 久久经典国产 | 911精品视频| 久久久精品综合 | 激情婷婷六月 | 黄色福利网站 | 在线中文字幕一区二区 | 免费在线电影网址大全 | 天堂资源在线观看视频 | 91精选在线观看 | 狠狠狠色丁香婷婷综合久久五月 | 日韩黄色一区 | 91av社区 | 亚洲视频在线播放 | 91在线视频免费播放 | 91在线免费视频 | 亚洲欧美日本国产 | 国产成人高清在线 | 18久久久久 | 欧美在线视频一区二区 | 日韩在线观 | 成人97视频 | 国产亚洲欧美精品久久久久久 | 久久国产精品系列 | 手机在线看片日韩 | 日韩欧美视频一区二区 | 在线观看国产www | 日韩免费网址 | 91精品视频免费在线观看 | 亚洲国产偷 | 97在线免费观看视频 | 国产精品欧美日韩在线观看 | 久久精品这里热有精品 | 久久久久久久久久久久久9999 | 99精品久久精品一区二区 | 91在线麻豆 | 久草免费在线观看 | 亚洲在线视频免费观看 | 国产精品久久久久四虎 | 中文字幕乱码电影 | 中文字幕日韩有码 | 麻豆91精品91久久久 | 成人免费在线播放视频 | 国产精品第一页在线 | 国产麻豆传媒 | 18久久久久久 | 久久精品国产免费 | 91精彩视频| 国产成人在线免费观看 | 亚洲综合小说电影qvod | 一区二区三区中文字幕在线 | 欧美一进一出抽搐大尺度视频 | av成人动漫在线观看 | av观看在线观看 | 国语久久 | 国产成人精品av在线观 | 精品视频www | 在线视频app | 激情综合一区 | 免费成人在线视频网站 | 国产精品久久久久亚洲影视 | 国产精品99久久久精品 | 在线成人短视频 | 天天爽天天摸 | 天天综合视频在线观看 | 婷婷六月天丁香 | 日本三级中文字幕在线观看 | 天天操天天爽天天干 | 成人免费毛片aaaaaa片 | 国产一区二区成人 | 亚洲精选在线 | 深夜免费福利 | 免费观看91视频 | 中文在线8新资源库 | 久久首页 | 不卡的av在线播放 | 一本一本久久a久久精品综合小说 | 色婷婷啪啪免费在线电影观看 | 精品日韩视频 | 亚洲婷婷免费 | 久久精品1区2区 | 久久五月天婷婷 | 麻豆国产精品视频 | 国产又粗又猛又色又黄网站 | 欧美一级黄大片 | 久久久久久久久久伊人 | 波多野结衣在线观看一区二区三区 | 中文在线a在线 | 色综合久久中文字幕综合网 | 在线国产91 | 欧美日韩一区二区三区免费视频 | 99精品久久99久久久久 | 亚洲成人精品久久 | 天天撸夜夜操 | 在线免费观看亚洲视频 | 日本精品一区二区 | 亚洲精品黄色 | 亚洲综合小说电影qvod | 久久激情视频 久久 | 国产成人精品久久久久蜜臀 | 久草在线中文视频 | h动漫中文字幕 | 欧美日韩国产综合网 | 日韩一区二区在线免费观看 | 国产最新在线观看 | 久久五月婷婷丁香 | 午夜精品av在线 | 成人小视频免费在线观看 | 最新av在线播放 | 永久免费av在线播放 | 欧美日韩xx | 波多野结衣电影一区 | 色五婷婷| 51久久成人国产精品麻豆 | 欧美性大战久久久久 | 91亚洲国产成人 | 久在线观看视频 | 日韩欧美成人网 | 小草av在线播放 | 亚洲精品国精品久久99热一 | 免费在线a| 成人免费观看完整版电影 | 欧美最猛性xxxxx(亚洲精品) | 亚洲精品国精品久久99热 | 四虎成人精品 | 99精品免费久久久久久久久日本 | av大全在线看| 欧美,日韩 | 天天综合网久久综合网 | 国产一区二区在线免费观看 | 免费成人结看片 | 91av在线国产 | 91在线观看视频 | 一区二区精品国产 | 全久久久久久久久久久电影 | 久久免费电影 | 久久中文字幕在线视频 | 91人人在线 | 女人高潮特级毛片 | 国产黄在线| 丰满少妇一级片 | 免费观看性生活大片 | 波多野结衣网址 | 久久精品精品 | 国产高清在线免费 | 久久精品国产亚洲aⅴ | 久久精品艹 | 超碰在线94 | 久久久久久久久久网站 | 日韩精品一区二区免费视频 | 麻豆视频在线看 | 欧美国产日韩激情 | 日韩午夜高清 | 欧美一区二区日韩一区二区 | 天天天天色射综合 | 日本不卡一区二区三区在线观看 | 亚洲激情综合网 | 成人av动漫在线 | av超碰在线观看 | 三级黄色大片在线观看 | 久久99久久精品 | 国产精选在线 | 日日摸日日碰 | 欧美视频二区 | 婷婷伊人综合亚洲综合网 | 久草剧场 | 伊人国产在线观看 | 久久久国产精品人人片99精片欧美一 | 五月婷婷一区 | 久久午夜色播影院免费高清 | 亚洲欧美日韩精品久久久 | 看全黄大色黄大片 | 99自拍视频在线观看 | 911精品美国片911久久久 | 在线 国产 亚洲 欧美 | 麻花豆传媒mv在线观看网站 | 国产亚洲精品久久网站 | 亚洲乱码在线观看 | 婷婷丁香五 | 日韩一级网站 | 国产精品免费久久久久久 | av中文字幕第一页 | 国产午夜影院 | 麻豆91精品91久久久 | 天天做天天爱夜夜爽 | 午夜在线观看一区 | 国产一区免费在线观看 | 色综合天天狠天天透天天伊人 | 亚洲精品国产精品国自产观看 | 日韩三级视频在线观看 | 中文在线a∨在线 | 国产精品久久久久久久久久久久久 | 黄色看片 | 欧美精品乱码久久久久久按摩 | 黄色在线观看污 | 国产精品欧美精品 | 日韩一区二区免费视频 | 深爱五月激情网 | 在线免费av观看 | 亚洲精品成人av在线 | 欧美精品一区二区在线观看 | 999热线在线观看 | 午夜久久福利影院 | 免费亚洲婷婷 | 久草视频在线免费看 | 婷婷中文在线 | 久久久久9999亚洲精品 | 欧美日韩久| 精品影院 | 国产高清无av久久 | 一级黄色片在线观看 | 亚洲天堂激情 | av免费在线看网站 | 婷婷国产精品 | 亚洲国产wwwccc36天堂 | 欧美 日韩 国产 成人 在线 | 国产精品一区二区三区免费视频 | 三级小视频在线观看 | 91.精品高清在线观看 | 欧美性成人 | 欧美男同网站 | 91丨九色丨国产丨porny精品 | 99精品视频精品精品视频 | 毛片永久免费 | 国色天香在线 | 欧美大荫蒂xxx | 久久最新视频 | 日韩电影中文,亚洲精品乱码 | 五月开心六月婷婷 | 国产精品毛片一区二区在线 | 久久久www成人免费精品张筱雨 | av丝袜在线 | 女人高潮一级片 | 免费高清在线视频一区· | 天天色天天色天天色 | 天天爱综合 | 中文字幕在线观看资源 | 色综合久久88色综合天天 | 国产99久久久精品 | 久久新视频 | 国产精品久久久久av免费 | 久久夜色精品国产欧美乱极品 | 国产精品综合av一区二区国产馆 | 美女视频黄免费的久久 | 久久精品毛片 | 国产成人精品一区二区三区网站观看 | 色综合久久久久久久久五月 | 日韩 精品 一区 国产 麻豆 | 久草免费手机视频 | 久久免费视频6 | 激情久久婷婷 | 97网站| 久久久官网 | 日本黄色免费大片 | 久久精品免费观看 | 69亚洲乱 | 国产精品麻 | 91精品国产欧美一区二区成人 | 国产成人一区二区三区 | 亚洲黄色在线 | 中文字幕超清在线免费 | 国产精品入口传媒 | 四虎欧美 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 黄色特一级片 | 欧美不卡视频在线 | 人人澡人人爱 | 四虎www. | 中文字幕999 | 日本黄区免费视频观看 | 97精品国产 | 人人干网站| 黄色国产在线观看 | 99久久精品国产网站 | 欧美婷婷色 | 日韩高清不卡在线 | 69亚洲乱 | 国产亚洲一区二区在线观看 | 久久不卡电影 | 色瓜| 国产黄色在线网站 | 久久久www成人免费精品 | 国产美腿白丝袜足在线av | 草久久久 | 精品欧美一区二区三区久久久 | 五月婷婷激情网 | 81精品国产乱码久久久久久 | 国产精品尤物 | 三级在线视频观看 | 午夜电影久久久 | 天天射天天操天天干 | 亚洲视频一区二区三区在线观看 | 国产四虎在线 | 久久 在线 | 精品国产乱码久久久久久1区二区 | 国产成人精品免高潮在线观看 | 国产精品区一区 | 在线视频你懂得 | 成人精品视频 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 成人毛片一区二区三区 | 久草在线久 | 欧美一级久久久久 | 久久久久久久久久久电影 | 欧美一二三区在线观看 | 国产免费二区 | 久久久久久久久久久久久久电影 | 亚洲最大色 | 2023av| 亚洲精品456在线播放 | 久久久网站 | 不卡av在线免费观看 | 九九免费观看全部免费视频 | 能在线观看的日韩av | .国产精品成人自产拍在线观看6 | 激情欧美一区二区三区免费看 | 婷婷丁香激情 | 最近最新最好看中文视频 | 欧美一级日韩免费不卡 | 亚洲狠狠婷婷综合久久久 | 免费三级大片 | 成人av在线播放网站 | 久久综合狠狠综合 | 日韩激情三级 | 欧美人zozo | 久久精品国产一区二区三 | 在线看一级片 | 久久久久久高潮国产精品视 | 伊人超碰在线 | 超碰免费在线公开 | 亚洲黄色免费观看 | 天天射色综合 | 色99之美女主播在线视频 | 在线日本看片免费人成视久网 | 人人爽人人搞 | 亚洲国产精品500在线观看 | 欧美性大战久久久久 | 日韩xxxxxxxxx | 亚州精品一二三区 | 欧美aa级 | 国产美女网站视频 | 中文在线a∨在线 | 麻豆视频网址 | 黄色网在线播放 | 日日爽| 成人av电影网址 | 亚洲第一中文字幕 | 伊人狠狠操 | 99热在线免费观看 | 在线国产99| 天天射天天爽 | 久久综合九色99 | 久久综合欧美精品亚洲一区 | 久久久久 | 国产精品麻豆99久久久久久 | 在线小视频国产 | 91精品蜜桃| 欧美日一级片 | 在线观看一级视频 | 欧美综合在线观看 | 中文字幕在线观看完整 | 久久久精品国产免费观看一区二区 | 国产成人一二三 | 五月天堂色 | 亚洲午夜久久久综合37日本 | 色综合天天综合 | 天天综合网在线 | 亚洲精品在线免费观看视频 | 亚洲在线精品视频 | 日韩美女av在线 | 亚洲第一香蕉视频 | .国产精品成人自产拍在线观看6 | 久久黄色网| 国产精品大片 | 免费在线看v | 久久综合欧美 | 国产亚洲视频在线 | 天天综合网久久综合网 | 在线观看黄色小视频 | 免费在线观看日韩 | 日韩网站在线播放 | 一区二区三区四区五区在线 | 久久久久久久久亚洲精品 | 99精品视频免费全部在线 | 国产永久免费观看 | 天天色天天射天天综合网 | 97天天综合网 | 久久免费的视频 | 免费高清在线观看成人 | 香蕉视频18| 香蕉影院在线 | 精品在线观看免费 | 精品视频在线免费 | 久草在线手机观看 | 日本中文一级片 | 国产a国产a国产a | 91精品国产三级a在线观看 | 欧美亚洲精品一区 | 精品国产理论 | 99久久婷婷国产一区二区三区 | 麻豆传媒视频在线 | 玖玖国产精品视频 | 黄色在线看网站 | 色射色 | 天天综合网国产 | 91精品福利在线 | 午夜日b视频 | 国产精品观看在线亚洲人成网 | 日夜夜精品视频 | 在线免费观看欧美日韩 | 中文字幕影片免费在线观看 | 久久蜜臀一区二区三区av | 日韩资源在线观看 | 在线视频日韩精品 | 天天操天天色天天 | 91精品久久久久 | 日韩视频在线观看免费 | 日批在线看| 草樱av | 一级黄色片在线免费看 | www.久久视频| 伊人久久在线观看 | 伊人国产在线播放 | 激情九九| 性色av免费在线观看 | 在线观看日韩一区 | 亚洲午夜久久久久久久久电影网 | 亚洲精选视频在线 | 国产超碰97 | 欧美精品首页 | a级片韩国| 国产精品99久久久久久久久久久久 | www.夜色321.com | 99久久99久久综合 | 日韩午夜电影网 | 日本一区二区三区免费观看 | 四虎成人精品永久免费av | av一区二区三区在线观看 | 黄色a视频| 在线观看黄 | 午夜影院一级片 | 草久久av| 久久综合欧美 | 色婷婷国产在线 | 韩日精品视频 | 2024av在线播放| 久久免费成人精品视频 | 国产精品久久中文字幕 | 在线看av的网址 | 日韩.com | 欧美一级片免费 | 亚洲无吗av | 伊人成人精品 | 亚洲专区免费观看 | 亚洲h色精品 | 欧美精品视 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | av高清网站在线观看 | 中文字幕国产视频 | 美女很黄免费网站 | 精品福利片 | 亚洲精品欧美成人 | 久久久国产精品久久久 | 国产成人精品一区二区在线 | 人人添人人澡人人澡人人人爽 | 国产精品女人久久久久久 | 日韩在线视频观看 | 99视频精品 | 摸阴视频 | 亚洲六月丁香色婷婷综合久久 | 亚洲欧美日韩不卡 | 日韩欧美国产免费播放 | 色在线观看网站 | 91精品视频在线观看免费 | 久久免费国产精品1 | 成人午夜电影久久影院 | 99精品在线播放 | 免费黄色在线网址 | 福利网址在线观看 | 视频国产精品 | 国产亚洲精品久久久久秋 | 中文字幕激情 | 免费看国产视频 | 天天天天爱天天躁 | 超碰人人av | 91精品视频免费看 | 国产福利精品视频 | 在线视频日韩一区 | 91精品啪啪 | 91精品爽啪蜜夜国产在线播放 | 日韩一级电影在线 | 99精品久久99久久久久 | 综合国产在线观看 | 国产精品av在线免费观看 | 在线免费高清视频 | 国产精品一区二区三区四区在线观看 | 亚洲综合色丁香婷婷六月图片 | a视频免费看 | www成人av | 91在线产啪| 国产精品一区二区无线 | 射九九| 亚洲欧美在线综合 | 97在线视频免费播放 | 久久免费电影网 | 免费一级日韩欧美性大片 | 国产高清av在线播放 | 日本性生活一级片 | 国产在线一区观看 | 天操夜夜操 | 一区二区 精品 | 69国产精品视频免费观看 | 精品999在线观看 | av播放在线| 婷婷色社区| 日韩免费在线 | 91成年视频 | 久草国产在线 | 91在线国产观看 | 国产福利精品一区二区 | 96亚洲精品久久久蜜桃 | 色婷婷av在线 | 久热国产视频 | 天天干天天天 | 国产剧在线观看片 | 国产在线a不卡 | 最近高清中文字幕 | 五月婷婷综合在线观看 | 国产无套精品久久久久久 | 成人午夜剧场在线观看 | 丁香 久久 综合 | 天天操夜操 | 免费福利在线观看 | www.99久久.com| 日韩精品高清不卡 | 草在线视频 | 成人黄色视 | 国内精品视频免费 | 99色99 | 最近最新mv字幕免费观看 | 天天干天天搞天天射 | 91| 日韩免 | 国产视频不卡一区 | 五月精品 | 中文字幕免费观看视频 | av综合 日韩 | 午夜神马福利 | 精品国产一区二区三区久久影院 | 91成人亚洲 | 亚洲精品在线资源 | 亚洲精品成人在线 | 美女视频久久久 | 日韩深夜在线观看 | 天天操天天拍 | 激情伊人五月天 | 91视频免费观看 | 麻豆国产网站 | 日本久久综合视频 | 亚洲成人黄色 | 欧美另类tv| 国产精品人人做人人爽人人添 | 久久激情视频免费观看 | 婷婷色网 | 欧美亚洲三级 | 日韩高清网站 | 国产亚洲免费观看 | 美女免费电影 |