`

IO 多路复用

阅读更多
作者:罗志宇
链接:http://www.zhihu.com/question/32163005/answer/55772739
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

假设你是一个机场的空管, 你需要管理到你机场的所有的航线, 包括进港,出港, 有些航班需要放到停机坪等待,有些航班需要去登机口接乘客。

你会怎么做?

最简单的做法,就是你去招一大批空管员,然后每人盯一架飞机, 从进港,接客,排位,出港,航线监控,直至交接给下一个空港,全程监控。

那么问题就来了:
  • 很快你就发现空管塔里面聚集起来一大票的空管员,交通稍微繁忙一点,新的空管员就已经挤不进来了。
  • 空管员之间需要协调,屋子里面就1, 2个人的时候还好,几十号人以后 ,基本上就成菜市场了。
  • 空管员经常需要更新一些公用的东西,比如起飞显示屏,比如下一个小时后的出港排期,最后你会很惊奇的发现,每个人的时间最后都花在了抢这些资源上。

现实上我们的空管同时管几十架飞机稀松平常的事情, 他们怎么做的呢?
他们用这个东西
<noscript>&lt;img src="https://pic2.zhimg.com/583d5ba3cee12e78befa8e2b749f4269_b.jpg" data-rawwidth="550" data-rawheight="534" class="origin_image zh-lightbox-thumb" width="550" data-original="https://pic2.zhimg.com/583d5ba3cee12e78befa8e2b749f4269_r.jpg"&gt;这个东西叫flight progress strip. 每一个块代表一个航班,不同的槽代表不同的状态,然后一个空管员可以管理一组这样的块(一组航班),而他的工作,就是在航班信息有新的更新的时候,把对应的块放到不同的槽子里面。</noscript> 这个东西叫flight progress strip. 每一个块代表一个航班,不同的槽代表不同的状态,然后一个空管员可以管理一组这样的块(一组航班),而他的工作,就是在航班信息有新的更新的时候,把对应的块放到不同的槽子里面。

这个东西现在还没有淘汰哦,只是变成电子的了而已。。

是不是觉得一下子效率高了很多,一个空管塔里可以调度的航线可以是前一种方法的几倍到几十倍。

如果你把每一个航线当成一个Sock(I/O 流), 空管当成你的服务端Sock管理代码的话.

第一种方法就是最传统的多进程并发模型 (每进来一个新的I/O流会分配一个新的进程管理。)
第二种方法就是I/O多路复用 (单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。)

其实“I/O多路复用”这个坑爹翻译可能是这个概念在中文里面如此难理解的原因。所谓的I/O多路复用在英文中其实叫 I/O multiplexing. 如果你搜索multiplexing啥意思,基本上都会出这个图:
<noscript>&lt;img src="https://pic1.zhimg.com/5d8e39d83e931da6ba3b6bc496302e5c_b.png" data-rawwidth="250" data-rawheight="177" class="content_image" width="250"&gt;</noscript> 于是大部分人都直接联想到"一根网线,多个sock复用" 这个概念,包括上面的几个回答, 其实不管你用多进程还是I/O多路复用, 网线都只有一根好伐。多个Sock复用一根网线这个功能是在内核+驱动层实现的

重要的事情再说一遍: I/O multiplexing 这里面的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态(对应空管塔里面的Fight progress strip槽)来同时管理多个I/O流. 发明它的原因,是尽量多的提高服务器的吞吐能力。

是不是听起来好拗口,看个图就懂了.

<noscript>&lt;img src="https://pic2.zhimg.com/18d8525aceddb840ea4c131002716221_b.jpg" data-rawwidth="400" data-rawheight="119" class="content_image" width="400"&gt;</noscript>
在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流, (学过EE的人现在可以站出来义正严辞说这个叫“时分复用”了)。

什么,你还没有搞懂“一个请求到来了,nginx使用epoll接收请求的过程是怎样的”, 多看看这个图就了解了。提醒下,ngnix会有很多链接进来, epoll会把他们都监视起来,然后像拨开关一样,谁有数据就拨向谁,然后调用相应的代码处理。

------------------------------------------
了解这个基本的概念以后,其他的就很好解释了。

select, poll, epoll 都是I/O多路复用的具体的实现,之所以有这三个鬼存在,其实是他们出现是有先后顺序的。

I/O多路复用这个概念被提出来以后, select是第一个实现 (1983 左右在BSD里面实现的)。

select 被实现以后,很快就暴露出了很多问题。
  • select 会修改传入的参数数组,这个对于一个需要调用很多次的函数,是非常不友好的。
  • select 如果任何一个sock(I/O stream)出现了数据,select 仅仅会返回,但是并不会告诉你是那个sock上有数据,于是你只能自己一个一个的找,10几个sock可能还好,要是几万的sock每次都找一遍,这个无谓的开销就颇有海天盛筵的豪气了。
  • select 只能监视1024个链接, 这个跟草榴没啥关系哦,linux 定义在头文件中的,参见FD_SETSIZE。
  • select 不是线程安全的,如果你把一个sock加入到select, 然后突然另外一个线程发现,尼玛,这个sock不用,要收回。对不起,这个select 不支持的,如果你丧心病狂的竟然关掉这个sock, select的标准行为是。。呃。。不可预测的, 这个可是写在文档中的哦.
“If a file descriptor being monitored by select() is closed in another thread, the result is unspecified”
霸不霸气

于是14年以后(1997年)一帮人又实现了poll, poll 修复了select的很多问题,比如
  • poll 去掉了1024个链接的限制,于是要多少链接呢, 主人你开心就好。
  • poll 从设计上来说,不再修改传入数组,不过这个要看你的平台了,所以行走江湖,还是小心为妙。
其实拖14年那么久也不是效率问题, 而是那个时代的硬件实在太弱,一台服务器处理1千多个链接简直就是神一样的存在了,select很长段时间已经满足需求。

但是poll仍然不是线程安全的, 这就意味着,不管服务器有多强悍,你也只能在一个线程里面处理一组I/O流。你当然可以那多进程来配合了,不过然后你就有了多进程的各种问题。

于是5年以后, 在2002, 大神 Davide Libenzi 实现了epoll.

epoll 可以说是I/O 多路复用最新的一个实现,epoll 修复了poll 和select绝大部分问题, 比如:
  • epoll 现在是线程安全的。
  • epoll 现在不仅告诉你sock组里面数据,还会告诉你具体哪个sock有数据,你不用自己去找了。

epoll 当年的patch,现在还在,下面链接可以看得到:
/dev/epoll Home Page

贴一张霸气的图,看看当年神一样的性能(测试代码都是死链了, 如果有人可以刨坟找出来,可以研究下细节怎么测的).
<noscript>&lt;img src="https://pic1.zhimg.com/5a56c4677da1c10153ed22a3f6dfeab4_b.png" data-rawwidth="640" data-rawheight="480" class="origin_image zh-lightbox-thumb" width="640" data-original="https://pic1.zhimg.com/5a56c4677da1c10153ed22a3f6dfeab4_r.png"&gt;</noscript>
横轴Dead connections 就是链接数的意思,叫这个名字只是它的测试工具叫deadcon. 纵轴是每秒处理请求的数量,你可以看到,epoll每秒处理请求的数量基本不会随着链接变多而下降的。poll 和/dev/poll 就很惨了。

可是epoll 有个致命的缺点。。只有linux支持。比如BSD上面对应的实现是kqueue。

其实有些国内知名厂商把epoll从安卓里面裁掉这种脑残的事情我会主动告诉你嘛。什么,你说没人用安卓做服务器,尼玛你是看不起p2p软件了啦。

而ngnix 的设计原则里面, 它会使用目标平台上面最高效的I/O多路复用模型咯,所以才会有这个设置。一般情况下,如果可能的话,尽量都用epoll/kqueue吧。

详细的在这里:
Connection processing methods

PS: 上面所有这些比较分析,都建立在大并发下面,如果你的并发数太少,用哪个,其实都没有区别。 如果像是在欧朋数据中心里面的转码服务器那种动不动就是几万几十万的并发,不用epoll我可以直接去撞墙了
参考:http://www.zhihu.com/question/32163005
分享到:
评论

相关推荐

    IO多路复用之select全面总结(必看篇)

    IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。 (2)当一个客户...

    io多路复用解析

    IO 多路复用解析 IO 多路复用是一种高效的输入/输出(I/O)管理机制,允许单个进程同时监控多个文件描述符(FD),以便在其中某个文件描述符上发生事件时,立即响应。IO 多路复用机制广泛应用于服务器端编程、网络...

    IO多路复用之poll——完整代码

    三种IO多路复用机制: 一:select 二:poll 三:epoll 以上三种IO多路复用的完整代码,皆可以在我的资源列表中获取下载: 资源列表:http://download.csdn.net/user/qiulanzhu

    IO多路复用实现TCPecho

    在IT领域,IO多路复用是一种高效地管理多个并发连接的技术,尤其在服务器端编程中,它能显著提升系统资源利用率和响应速度。本文将深入探讨如何利用IO多路复用来实现一个TCP echo服务器,该服务器运行在Linux环境下...

    io多路复用的本质(png)

    io多路复用帮助你更快更轻松的掌握多并发服务器的搭建

    2-2、非阻塞套接字与IO多路复用 学习PPT

    非阻塞套接字与IO多路复用学习PPT 非阻塞套接字与IO多路复用是计算机网络编程中两个重要的概念。非阻塞套接字是一种特殊的套接字,它可以在不阻塞当前进程的情况下,等待数据的到达。IO多路复用是一种机制,允许...

    io多路复用服务器-聊天室.zip

    【标题】"io多路复用服务器-聊天室"指的是一个使用Python编程语言构建的服务器,它基于IO多路复用技术实现,可以处理多个客户端连接请求,用于创建一个聊天室应用。IO多路复用是一种高效的服务端设计模式,通过监听...

    IO多路复用之poll实例

    在计算机编程领域,IO多路复用是一种高效地管理多个输入/输出(I/O)操作的技术,它允许程序同时等待多个文件描述符的事件。在Linux系统中,`poll`函数是实现IO多路复用的一种方法。在这个“IO多路复用之poll实例”...

    IO多路复用select和epoll.md

    多路复用

    python3多进程多线程协程IO多路复用等

    对python并发进行的笔记整理,个人所学习使用,主要包括多进程,多线程,协程,IO多路复用,进程线程通信等

    IO多路复用之select实例

    **IO多路复用之select实例详解** IO多路复用是一种高效的系统调用机制,它允许单个进程同时监控多个文件描述符(file descriptor),等待它们中的任意一个或多个准备就绪,以便进行读写操作。在Unix/Linux系统中,...

    IO多路复用之epoll——完整代码

    三种IO多路复用机制: 一:select 二:poll 三:epoll 以上三种IO多路复用的完整代码,皆可以在我的资源列表中获取下载: 资源列表:http://download.csdn.net/user/qiulanzhu

    IO多路复用图解1

    在计算机编程领域,IO多路复用是一种提高服务器性能的技术,尤其在处理大量并发连接时。该技术的主要目的是通过一个单独的线程或进程来管理多个IO操作,从而避免为每个连接创建单独的线程或进程,这样可以节省资源并...

    io多路复用c语言版简单http服务器demo

    IO多路复用是一种操作系统提供的机制,允许单个进程监视多个文件描述符(例如,套接字),等待数据到达或可写入。在C语言中,通常使用`select`或`poll`系统调用来实现。在这个HTTP服务器中,`select`被用来监听...

    month02_IO多路复用方法对比.md

    ### IO多路复用方法对比 #### 概述 在计算机网络编程中,为了提高程序对多个文件描述符(如套接字)的监控效率,引入了多种IO多路复用技术。这些技术允许程序同时监控多个文件描述符的状态变化,并在其中一个或多...

    1.18 第六章 IO多路复用

    1.18 第六章 IO多路复用

    windows下多路复用IO(select,WSAAsyncSelect,WSAEventSelect)

    在Windows操作系统中,多路复用I/O(Multiplexed Input/Output)是一种高效地管理多个网络连接的技术,它允许程序同时处理多个套接字事件,而无需为每个连接创建单独的线程或进程。本篇文章将深入探讨三种在Windows...

    IO多路复用.md

    ### IO多路复用详解及实现方式 #### 同步与异步、阻塞与非阻塞 在探讨IO多路复用之前,先来理解几个基础概念:同步与异步、阻塞与非阻塞。 - **同步**:同步是指在发起一个请求后必须等待该请求被处理完毕才能...

    基于TCP协议分别使用多线程、IO 多路复用的方法实现多人聊天室(python).zip

    下面我们将详细探讨TCP协议、多线程和IO多路复用等关键知识点。 首先,TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它确保数据包按照发送顺序正确无误地到达目的地,通过三次握手...

    IO多路复用之select——完整代码

    三种IO多路复用机制: 一:select 二:poll 三:epoll 以上三种IO多路复用的完整代码,皆可以在我的资源列表中获取下载: 资源列表:http://download.csdn.net/user/qiulanzhu

Global site tag (gtag.js) - Google Analytics