这篇文章的结论就是epoll属于同步非阻塞模型,这个东西貌似目前还是有争议,在新的2.6内核之后,epoll应该属于异步io的范围了,golang的高并发特性就是底层封装了epoll模型的函数,但也有文章指出epoll属于“伪AIO”,真正的推动力实际在系统内核,另外mmap的应用加快了用户层和内核层的消息交换,对并发效率也有极大的提升。
还有一点,在DMA控制器的帮助下,实际上算是异步了,所以epoll可以说就是异步非阻塞。

《UNIX网络编程:卷一》第六章——I/O复用。书中向我们提及了5种类UNIX下可用的I/O模型:

  • 阻塞式I/O;

  • 非阻塞式I/O;

  • I/O复用(select,poll,epoll...);

  • 信号驱动式I/O(SIGIO);

  • 异步I/O(POSIX的aio_系列函数);

阻塞式I/O模型:默认情况下,所有套接字都是阻塞的。怎么理解?先理解这么个流程,一个输入操作通常包括两个不同阶段:

(1)等待数据准备好;

(2)从内核向进程复制数据。

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。 好,下面我们以阻塞套接字的recvfrom的的调用图来说明阻塞

<img src="https://pic2.zhimg.com/50/e83d68da03da2e8c1568b4b4b630edfd_hd.jpg" data-rawwidth="1058" data-rawheight="556" class="origin_image zh-lightbox-thumb" width="1058" data-original="https://pic2.zhimg.com/e83d68da03da2e8c1568b4b4b630edfd_r.jpg">

标红的这部分过程就是阻塞,直到阻塞结束recvfrom才能返回。

非阻塞式I/O: 以下这句话很重要:进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。看看非阻塞的套接字的recvfrom操作如何进行

<img src="https://pic1.zhimg.com/50/4bc31cab27a9a732ab7d1ba9e674ed64_hd.jpg" data-rawwidth="1064" data-rawheight="631" class="origin_image zh-lightbox-thumb" width="1064" data-original="https://pic1.zhimg.com/4bc31cab27a9a732ab7d1ba9e674ed64_r.jpg">

可以看出recvfrom总是立即返回。

I/O多路复用:虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。如图

<img src="https://pic1.zhimg.com/50/b1ec6a4f16844a27c175d5a6a94cd7f8_hd.jpg" data-rawwidth="1136" data-rawheight="732" class="origin_image zh-lightbox-thumb" width="1136" data-original="https://pic1.zhimg.com/b1ec6a4f16844a27c175d5a6a94cd7f8_r.jpg">

信号驱动式I/O:用的很少,就不做讲解了。直接上图

<img src="https://pic1.zhimg.com/50/6294fb7f7f5c22e39187a490c35ac6f0_hd.jpg" data-rawwidth="1139" data-rawheight="711" class="origin_image zh-lightbox-thumb" width="1139" data-original="https://pic1.zhimg.com/6294fb7f7f5c22e39187a490c35ac6f0_r.jpg">

异步I/O:这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。如图:

<img src="https://pic2.zhimg.com/50/5819fd0fdff2bd4fdc9652291aca1831_hd.jpg" data-rawwidth="1109" data-rawheight="603" class="origin_image zh-lightbox-thumb" width="1109" data-original="https://pic2.zhimg.com/5819fd0fdff2bd4fdc9652291aca1831_r.jpg">

注意红线标记处说明在调用时就可以立马返回,等函数操作完成会通知我们。

等等,大家一定要问了,同步这个概念你怎么没涉及啊?别急,您先看总结。 其实前四种I/O模型都是同步I/O操作,他们的区别在于第一阶段,而他们的第二阶段是一样的:在数据从内核复制到应用缓冲区期间(用户空间),进程阻塞于recvfrom调用。相反,异步I/O模型在这两个阶段都要处理。

<img src="https://pic4.zhimg.com/50/8244d924a12eaf42d61b41718c559bff_hd.jpg" data-rawwidth="3200" data-rawheight="1800" class="origin_image zh-lightbox-thumb" width="3200" data-original="https://pic4.zhimg.com/8244d924a12eaf42d61b41718c559bff_r.jpg">

再看POSIX对这两个术语的定义:

  • 同步I/O操作:导致请求进程阻塞,直到I/O操作完成;

  • 异步I/O操作:不导致请求进程阻塞。

好,下面我用我的语言来总结一下阻塞,非阻塞,同步,异步

  • 阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;

  • 同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写。



这是一次概念的纠结过程,对写代码没有太大意义。

过程是这样的:
首先,我的概念里往往只有同步和异步,没有太多去区别同异步IO和同异步通知两种。
另外还记得apu(2rd)中有一句“select和poll可以实现异步形式的通知”。

接着,听到了epoll是同步IO这个概念,比较意外。坚持了一下后,查到如下概念:
在unp(3rd)里的定义是:
第一是IO操作的概念:
IO操作包括:
1.等待数据准备好。
2.从内核到进程拷贝数据。

第二就是是同步IO和异步IO的区别:
同步IO导致请求进程阻塞,直到IO操作完成。
异步IO不导致请求进程阻塞。

得到的结论:
阻塞IO模型,非阻塞IO模型,IO复用模型,信号驱动IO模型都是同步IO。
epoll也是IO复用模型,应该是同步IO。

此时又意外了,再看到一个解释:
更为重要的是, epoll 因为采用 mmap的机制, 使得 内核socket buffer和 用户空间的 buffer共享, 从而省去了 socket data copy, 这也意味着, 当epoll 回调上层的 callback函数来处理 socket 数据时, 数据已经从内核层 "自动" 到了用户空间, 虽然和 用poll 一样, 用户层的代码还必须要调用 read/write, 但这个函数内部实现所触发的深度不同了.

用 poll 时, poll通知用户空间的Appliation时, 数据还在内核空间, 所以Appliation调用 read API 时, 内部会做 copy socket data from kenel space to user space.

而用 epoll 时, epoll 通知用户空间的Appliation时?, 数据已经在用户空间, 所以 Appliation调用 read API 时?, 只是读取用户空间的 buffer, 没有 kernal space和 user space的switch了.

于是想了一下:
明显没有IO操作的拷贝数据到内核空间了,stevens应该在99年就挂了,2.6内核的epoll才采用mmap机制,书籍偏旧了吧。
那么epoll是异步IO了吧。

然后再一看,你妹的,这还是不符合异步IO啊,毕竟epoll在告知OK前,是阻塞了,虽然是拷贝数据结束了。
看来好像应该修正的是IO操作定义的第二步才对,而不是那个区别。

好吧,你就暂时属于同步IO了,专心看代码,不纠结概念了。

关于epoll的IO模型是同步异步的一次纠结过程的更多相关文章

  1. Linux的五种IO模型及同步和异步的区别

    前置知识 缓存 I/O 缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操作都是缓存 I/O.在 Linux 的缓存 I/O 机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓 ...

  2. 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...

  3. 转 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

    此文章为转载,如有侵权,请联系本人.转载出处,http://blog.chinaunix.net/uid-28458801-id-4464639.html 同步(synchronous) IO和异步( ...

  4. Linux IO模型(同步异步阻塞非阻塞等)的几篇好文章

    聊聊同步.异步.阻塞与非阻塞聊聊Linux 五种IO模型聊聊IO多路复用之select.poll.epoll详解 ​

  5. IO模型:同步、异步、阻塞、非阻塞

    前言: 在Linux的网络编程中,同步IO(synchronous IO).异步IO(asynchronous IO).阻塞IO(blocking IO).非阻塞IO(non-blocking IO) ...

  6. 5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO

    POSIX 同步IO.异步IO.阻塞IO.非阻塞IO,这几个词常见于各种各样的与网络相关的文章之中,往往不同上下文中它们的意思是不一样的,以致于我在很长一段时间对此感到困惑,所以想写一篇文章整理一下. ...

  7. IO模型分析

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  8. 五种IO模型透彻分析

    1.基础 在引入IO模型前,先对io等待时某一段数据的"经历"做一番解释.如图: 当某个程序或已存在的进程/线程(后文将不加区分的只认为是进程)需要某段数据时,它只能在用户空间中属 ...

  9. 并发编程——IO模型(6)

    1.IO模型分类 同步IO #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不会返回.按照这个定义,其实绝大多数函数都是同步调用.但是一般而言,我们在说同步.异步的时候,特指那些需要 ...

随机推荐

  1. MYSQL语句:创建、授权、查询、修改、统计分析等 一 用户的创建、权限设置、删除等

    MYSQL语句:创建.授权.查询.修改.统计分析.. 一.用户的创建.权限设置.删除等 1.首先链接MySQL操作 连接格式:mysql -h 主机地址 -u 用户名 -p 用户密码 (注-u与roo ...

  2. python删除所有自定义变量方法--转载

    http://blog.sina.com.cn/s/blog_b2f983a50102yexs.html   当我们在pythonwin中创建多个变量后,通过dir()函数,可以看到所有已创建变量,这 ...

  3. 4:JavaScript中的对象

    对象 --属性+方法(都可以添加) ------继承关系------------原型(类) 获取变量属性:obj.x或者obj[“x”]: this对象----a---范围 arguments对象 参 ...

  4. 说说前端那些事之ajax

    原生ajax请求 前些日子,忙着考驾照,没有时间对知识进行总结,感到十分惭愧啊,刚好趁现在有时间,做个知识总结,希望对各位有所帮助. 很多人都知道ajax是用来进行数据请求的,但是具体的请求方法会有些 ...

  5. Java中的正则表达式Pattern与Matcher

    一般来说比起功能有限的String类,我们更愿意构造功能强大的正则表达式.我们可以通过Pattern 与 Matcher 来构建功能强大的正则表达式 import java.io.File; impo ...

  6. Jenkins 构建 coding项目,插件

    安装插件:http://updates.jenkins-ci.org/download/plugins/coding-webhook/

  7. Enumerable扩展方法

    主要记录一些平时在工作中用到操作Enumerable的常用方法 /// <summary> /// The i enumerable extension. /// </summary ...

  8. 《剑指offer》第十五题(二进制中1的个数)

    // 面试题:二进制中1的个数 // 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如 // 把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2. #inclu ...

  9. hihoCoder 1636 Pangu and Stones

    hihoCoder 1636 Pangu and Stones 思路:区间dp. 状态:dp[i][j][k]表示i到j区间合并成k堆石子所需的最小花费. 初始状态:dp[i][j][j-i+1]=0 ...

  10. 『cs231n』视频数据处理

    视频信息 和我之前的臆想不同,视频数据不仅仅是一帧一帧的图片本身,还包含个帧之间的联系,也就是还有一个时序的信息维度,包含人的动作判断之类的任务都是要依赖动作的时序信息的 视频数据处理的两种基本方法 ...