多种I/O模型及其对socket效率的改进

在读redis源代码的过程中,我一直在考虑一个问题,就是“为什么单线程的redis能做到如此高效?”。为了弄清楚这个问题,我查阅了一些资料,大概搞清楚了epoll等I/O模型的发展及其原理,以下是一个记录整理。

##I/O模型

###操作系统与网络I/O

上图来自维基百科,是一个基本的计算机结构。计算机主要完成两个工作,运算和I/O。因为CPU处理效率以及各种设备的I/O效率千差万别,所以协调I/O提高效率是操作系统的一个重要任务。各种I/O模型应运而生。

####同步和异步

计算机任务执行的实体是进程,进程和I/O的关系需要理清。根据执行I/O时进程的状态,可以把I/O操作分为同步和异步两种方式。

* 同步IO操作:引起进程的阻塞直到IO操作完成

* 异步IO操作:IO操作不会引起进程阻塞

其中同步和异步指进程和IO的关系,阻塞和非阻塞指进程的状态。结合操作系统的进程管理,可以认为最优的状态是:a)进程完全不被影响,继续执行直到I/O完成再处理 b)进程完全挂起,把资源交给其他进程,I/O完成后再醒来继续执行。

###网络IO模型

####阻塞IO

最基础的方式,问题在于进程阻塞于一个IO就不能响应其他请求,效率很低。

####非阻塞IO

使用轮询的方式,会占用大量的计算资源,应该只有特殊情况才会使用到。

####IO复用

关键在于复用,一个进程可以一次性等待多个IO。

####信号驱动IO

使用范围很小,在TCP下信号产生的过于频繁难以区分含义,所以只在使用UDP协议的程序中应用。“作者能找到的实际使用信号驱动的I/O程序是基于UDP的NTP服务器程序”。与异步IO的理念区别仅仅在于是否由操作系统自动拷贝数据到内核空间,我不明白为什么不直接发展成异步IO,反而要加入这个模型。

####异步IO

整个过程进程都是非阻塞的。

前4种都是同步的,第5种是异步

##socket

###socket基本概念

socket工作在会话层以上,通过绑定并监听指定端口,接收数据。

###socket示例

最简单的accept()方式是阻塞的,在建立连接之前程序挂起。可以使用while循环accept,不过这种方式read()也是阻塞的,所以在第一个连接结束之前,第二个连接无法被处理。

写代码中的两个有趣的点:

* listen函数的backlog有一个magic number 511

* close()之后有一个time_wait的过程,这时候如果再绑定相同端口会失败,可以使用setsockopt()

##改进

###使用多进程改进

在while循环中,每次accept就fork出一个新进程,这样就能同时处理多个连接。这里需要处理父进程与子进程的关系,引用计数,信号处理等问题。而且每次创建销毁进程消耗较大。

###使用select改进

在while循环中,使用select监听一个fd集合,当其中的fd可读/写/异常时从阻塞恢复。可以同时监听多个fd。当然读写也会阻塞,所以要配合多进程/多线程使用。因为不需要每个连接就生成一个新进程,比fork的方式要更优化。

存在的问题是:

* fd数量有限

* 每次都循环检查所有fd效率低

* 用户态和内核态内存拷贝效率低

###使用epoll改进

epoll针对select的问题做了优化:

* 上限是最大可以打开文件的数目

* 只关注“活跃”的链接不用循环检查

* 使用内存共享避免拷贝

使用epoll 主要调用3个API :

int epoll_create(int size); //2.6.8之后size参数被忽略,参考
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

另外特别需要注意的是水平触发(LT)和边缘触发(ET)的概念,以及events的处理(出错,client关闭等等)。

以上几种方式我都简单实现了,代码见【20】。

###性能对比测试

这篇论文【18】  对select/poll/epoll的性能做了对比测试。可以看出在所有I/O都活跃的情况下,select和epoll的性能相近。但存在大量空闲连接时,epoll的性能就明显高于select了,这与epoll的改进思路是相符合的。

在查找资料的过程中,我发现大部分资料都语焉不详或者思路不清晰。所以把IO和socket作为前置知识,结合了一些代码示例。希望应该能更好的理清思路,理解I/O模型为什么要这样设计和实际应用中为什么要这样改进。写的东西不多,干货都在参考文章中。

参考

【1】Unix 五种基本I/O模型的区别 - 语行 - 博客园

【2】Operating Systems: I/O Systems

【3】OSI model - Wikipedia, the free encyclopedia

【4】简单理解Socket - dolphinX - 博客园

【5】Linux Howtos: C/C++ -> Sockets Tutorial

【6】linux文件设备与I/O:read/write函数 与 阻塞 Block_面包坊_百度空间

【7】socket编程-listen函数之backlog_飞翔的鱼在北京_新浪博客

【8】[C/C++] 解決Socket連續Bind同一個Port的問題 | 不務正業紀實

【9】linux 多进程 缺点 - 网摘记录 - ITeye技术网站

【10】The GNU C Library: Server Example

【11】Linux Epoll介绍和程序实例 - sparkliang的专栏 - 博客频道 - CSDN.NET

【12】Linux下select, poll和epoll IO模型的详解 - tianmo2010的专栏 - 博客频道 - CSDN.NET

【13】UNIX网络编程--I/O复用:select函数和poll函数讲解(六) - 鱼思故渊的专栏 - 博客频道 - CSDN.NET

【14】epoll 或者 kqueue 的原理是什么? - 知乎 Epoll detailed

【15】How to use epoll? A complete example in C - Banu Blog

【16】epoll(4): I/O event notification facility - Linux man page

【17】epoll_create(2): open epoll file descriptor - Linux man page

【18】https://www.kernel.org/doc/ols/2004/ols2004v1-pages-215-226.pdf

【19】networking - Caveats of select/poll vs. epoll reactors in Twisted - Stack Overflow

【20】mickhan/socket_demo

【21】unix下的I/O------阻塞,非阻塞,同步,异步 - 51CTO.COM

时间: 2024-10-06 10:12:13

多种I/O模型及其对socket效率的改进的相关文章

多种贝叶斯模型构建文本分类

多种贝叶斯模型构建及文本分类的实现 作者:白宁超 2015年9月29日11:10:02 摘要:当前数据挖掘技术使用最为广泛的莫过于文本挖掘领域,包括领域本体构建.短文本实体抽取以及代码的语义级构件方法研究.常用的数据挖掘功能包括分类.聚类.预测和关联四大模型.本文针对四大模型之一的分类进行讨论.分类算法包括回归.决策树.支持向量机.贝叶斯等,显然,不少涉及机器学习的知识(随后会写些机器学习专题).本文重点介绍贝叶斯分类,涉及朴素贝叶斯模型.二项独立模型.多项模型.混合模型等知识.在本人研究贝叶斯

效率管理改进

效率管理改进 又是崭新的一月,前面一直在给大家分享软件测试方面的心得,今天我们换种"口味",这些都是平时工作中总结沉淀的,也是一直困扰着我,我相信大家也会遇到类似情况. 分享之前,我们还是从某个Scene开始吧!平时工作中,现在有个A项目测试任务正做着,突然运营部说B项目本周要急着上线,希望能够检测下这个软件现有功能情况.现在就放下A项目这边的事情去介入B项目的工作,刚做了一半,然后 另外一个团队小伙伴说C项目有个功能已基本完成,需要测试帮忙跟进一下,也挺急的,那么接着又放下手中的事情

UNIX DOMAIN SOCKET效率

关于UNIX DOMAIN SOCKET和普通udp socket的对比 在TX1(4核A57 1.7GHz)的板卡上进行测试,每个包大小设置为1024,全速收发,UDS的速度在90Mbps左右,UDP在120Mbps左右(略有丢包) CPU占用率,UDS比UDP低10%,但是实际上,如果码率相近时,CPU占用率是差不多的 下面是UDP的CPU占用: top - 08:44:46 up 3:04, 5 users, load average: 1.78, 1.70, 1.66 Threads:

高性能Socket模型

1. 常见的Socket模型 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK.注意这里所说的NIO并非Java的NIO(New IO)库. (3)IO多路复用(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Select

Python socket编程之IO模型介绍(多路复用*)

1.I/O基础知识 1.1 什么是文件描述符? 在网络中,一个socket对象就是1个文件描述符,在文件中,1个文件句柄(即file对象)就是1个文件描述符.其实可以理解为就是一个“指针”或“句柄”,指向1个socket或file对象,当file或socket发生改变时,这个对象对应的文件描述符,也会发生相应改变. 1.2 什么是I/O 1.先了解什么是I/O? I/O(input/output),即输入/输出.操作系统会对IO设备进行编址,IO设备用操作系统分配的地址来处理自己的输入输出信息.

socket编程的select模型

在掌握了socket相关的一些函数后,套接字编程还是比较简单的,日常工作中碰到很多的问题就是客户端/服务器模型中,如何让服务端在同一时间高效的处理多个客户端的连接,我们的处理办法可能会是在服务端不停的监听客户端的请求,有新的请求到达时,开辟一个新的线程去和该客户端进行后续处理,但是这样针对每一个客户端都需要去开辟一个新的线程,效率必定底下. 其实,socket编程提供了很多的模型来处理这种情形,我们只要按照模型去实现我们的代码就可以解决这个问题.主要有select模型和重叠I/o模型,以及完成端

通过实例理解Java网络IO模型

网络IO模型及分类 网络IO模型是一个经常被提到的问题,不同的书或者博客说法可能都不一样,所以没必要死抠字眼,关键在于理解. Socket连接 不管是什么模型,所使用的socket连接都是一样的.以下是一个典型的应用服务器上的连接情况.客户的各种设备通过Http协议与Tomcat进程交互,Tomcat需要访问Redis服务器,它与Redis服务器也建了好几个连接.虽然客户端与Tomcat建的是短连接,很快就会断开,Tomcat与Redis是长连接,但是它们本质上都是一样的.建立一个Socket后

从BSP模型到Apache Hama

? 什么是BSP模型 概述 BSP(Bulk Synchronous Parallel,整体同步并行计算模型)是一种并行计算模型,由英国计算机科学家Viliant在上世纪80年代提出.Google发布的一篇论文(<Pregel: A System for Large-Scale Graph Processing>)使得这一概念被更多人所认识,据说在Google 80%的程序运行在MapReduce上,20%的程序运行在Pregel上.和MapReduce一样,Google并没有开源Pregel

高性能IO模型浅析(转)

转自:http://www.cnblogs.com/fanzhidongyzby/p/4098546.html 是我目前看到的解释IO模型最清晰的文章,当然啦,如果想要详细的进一步了解还是继续啃蓝宝书吧. 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK.注意这里所说的NIO