朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较
经过之前四篇博文的介绍,可以大致清楚各种模型的编程步骤。现在我们来回顾下各种模型(转载请指明出于breaksoftware的csdn博客)
模型编程步骤对比
《朴素、Select、Poll和Epoll网络编程模型实现和分析——朴素模型》中介绍的是最基本的网络编程模型,我们使用单线程去实现,它的步骤很简单
如同这幅流程图,它简单到非常单薄。这个模型暴露出来的问题是在一个线程中,它一次只能处理一个请求。当然我们可以通过多线程或者多进程的模式对该模型进行改进:主线程监听接入socket请求,将其保存到一段空间中。其他线程从该段空间中获取socket并处理。但是这种改善不是从网络编程模型的角度出发的,而是多线程/多进程的一种应用,这种应用也可以用于之后几个模型。所以我们暂且抛开这种优化来讨论。
《朴素、Select、Poll和Epoll网络编程模型实现和分析——Select模型》解决了朴素模型同步的执行的问题,而且还解决了一次只能处理一个请求的问题。
可以见得这种模型稍微厚实了一点,但是它也有一个问题:最多只能同时处理1024个请求。致命的是这种限制是在内核代码级别的(详见之前文章的分析)。为了解决这个问题于是就有了poll模型。
《朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll模型》中介绍的Poll模型结构和Select模型是非常相似的,但是它不再依赖于结构体的位数来限制最多处理的socket数,而是采用一个数组去保存数据。
poll模型的问题是其效率随着同时连接的socket数而下降。因为它和Select模型有着相同的缺陷——每次只是知道有事件发生,但是不知道是哪个socket有事件发生,于是需要遍历所有的socket。这样socket如果越来越多,它的效率自然会下降。为了解决这个问题,于是有了Epoll模型。
《朴素、Select、Poll和Epoll网络编程模型实现和分析——Epoll模型》算是目前最优秀的解决多连接的模型。但是它也是最复杂的模型。
模型效率对比
首先明确一个立场,没有实际测试数据的对比都是空谈。网上一般充斥的一种观点就是EPOLL模型效率最好,Poll和Select模型相当,朴素模型最差。但是这个观点是错误的。因为不同的模型在不同的使用场景下有着不同的效率。
比如,在我们之前测试的场景下。朴素模型的平均处理能力大概是15000次/秒,Select的平均处理能力是7000次/秒,Poll的平均处理能力是7500次/秒,Epoll的平均处理能力是11000次/秒。为什么朴素模型的处理能力是最高的?因为我们这个是一个典型的短连接、一次性交互的场景,这种场景下如果得到一个请求马上去读和写,而不经过其他复杂的过程,自然是最快的。Poll模型和Select模型能力相当。Epoll是对Poll模型的优化,所以它的效率比Select和Poll要好一些。
我们使用valgrind对上述四种模型的执行情况进行分析。
首先我们看朴素模型
朴素模型的main函数自身(即刨除下面列出的函数的其他执行时间)的执行时间占比是非常小的(5.45%),其主要的耗时操作是读和写操作(server_write占38.94%,server_read占27.64%)。
我们再看下效率第二的Epoll模型
可见Epoll模型中,server_write操作耗时占比最高(29.32%),其次是main函数自身耗时占(25.7%),再次是server_read(22.48%)。
再看下效率倒数第二的Poll模型
Poll模型中main函数自身耗时占比最高(46.93%),其次是server_write(21.44%),再次是server_read(16.44%)。我们看到main函数自身耗时提高非常多。
最后我们看看效率最低的Select模型
Select模型中,main函数自身耗时占比最多(97.99%),其次是server_write(0,83%),再次是server_read(0.64%)。那么main函数中什么是最耗时的呢?我对Select模型源码进行了细分,将之前循环遍历各个Socket的逻辑提炼出来
void deal_socket(int index, int listen_sock, fd_set* active_fd_set, fd_set* read_fd_set) {if (listen_sock == index) {/* Connection request on original socket. */int new_sock;new_sock = accept(listen_sock, NULL, NULL);if (new_sock < 0) {perror("accept error");exit(EXIT_FAILURE);}request_add(1);FD_SET(new_sock, active_fd_set);} else {if (0 == server_read(index)) {server_write(index);}close(index);FD_CLR(index, active_fd_set);}
}void deal_request(int listen_sock, fd_set* active_fd_set, fd_set* read_fd_set) {int index = 0;for (index = 0; index < FD_SETSIZE; ++index) {if (FD_ISSET(index, read_fd_set)) {deal_socket(index, listen_sock, active_fd_set, read_fd_set);}}
}
再进行测试,我们得出以下结果
deal_request函数函数内部理论上最大调用deal_socket的次数是30万*1024=3072万,而实际调用deal_socket的次数只有60万。这说明平均一次调用deal_request只会有2个socket被命中从而调用deal_socket。也就是说,1次select操作只有2个socket会被处理,而其他1022次循环操作都是不被命中的比较。而恰恰最耗时的就是deal_request操作(deal_socket操作占用deal_request时间不足2%),所以我们可以得出select模型中最耗时的就是对socket的遍历操作。而其根本原因是select函数每次返回时可以被处理的socket数量太少——2个。
那么epoll和poll模型的循环使用率是多少?我们对它们的代码做点改造,我们引入两个标记函数——total_loop_count和deal_sock_count,前者用于统计一共循环了多少次,后者用于统计需要处理的socket多少次。我们先看Poll模型的结果。
可见Poll模型中对pollfd数组遍历的次数一共是60万次,有效处理socket也是60万次。使用率100%,而不像Select模型的使用率只有60/3072=2%。同样epoll的使用率也是100%。
通过上述分析,我们可以看出在短连接、一次性读写完数据的情况下,朴素模型的效率是最高的,其次是Epoll、Poll、Select。其实Select模型性能和Poll是差不多的,在我们测试场景下产生的差距是因为我们实现Select模式的方式问题。我们对其可以参照Poll模型进行改造,使用一个int型数组保存接入的socket,同时动态记录可用socket的个数。这样我们每次遍历就只遍历连续的可用socket数组空间,而不用像例子中将整个数组都遍历,从而提高循环操作的有效率。
那么什么时候才是该使用Select、Poll或者Epoll模型的呢?我们将在下一篇博文中对其进行分析。
相关文章:

使用VM虚拟机的一点小技巧
今天想为朋友弄一个虚拟机系统文件,这样就可以直接拷贝过去,直接让他用了。哪成想电脑里的系统镜像文件不能用,也不知道是不是VM不支持,反正怎么着也引导不起来了。无奈只好用硬件光驱来装虚拟系统,把2003系统盘装入光…
翻译:AKKA笔记 - Actor消息 -1(二)
消息 我们只是让QuoteRequest到ActorRef去但是我们根本没见过消息类! 它是这样的:(一个最佳实践是把你的消息类包装在一个完整的对象里以利于更好的组织) TeacherProtocol package me.rerun.akkanotes.messaging.protocolsobject …

远程安装oracle 10.2.1 for redhat 5.0 2.6.18-53.el5xen
远程安装oracle <?xml:namespace prefix st1 ns "urn:schemas-microsoft-com:office:smarttags" />10.2.1 for redhat 5.0 2.6.18-53.el5xen<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />今天有个朋友打电…
伯克利新无监督强化学习方法:减少混沌所产生的突现行为
作者 | Glen Berseth译者 | Arvin编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100)【导读】所有生命有机体都在环境中占据一席之地,使它们在周围不断增加的熵中可以保持相对可预测性。例如,人类竭尽全力保护自己免受意外袭击--我们…
朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较
在《朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较》一文中,我们分析了各种模型在处理短连接时的能力。本文我们将讨论处理长连接时各个模型的性能。(转载请指明出于breaksoftware的csdn博客) 我们可以想象下场景,…

Topcoder SRM 663 DIV 1
ABBADiv1 题意: 规定两种操作,一种是在字符串的末尾添加A,另一种是在末尾添加B然后反转字符串。现在给你一个起始串,一个终点串,然后问你是否能够通过以上两种操作,从起始串变为终点串。 题解: …
跨平台PHP调试器设计及使用方法——立项
作为一个闲不住且希望一直能挑战自己的人,我总是在琢磨能做点什么。自从今年初开始接触PHP,我也总想能在这个领域内产生点贡献。那能做点什么呢?我经常看到很多phper说自己设计了一个什么框架,或者说自己搭建了一个什么系统。虽然…
机器推理文本+视觉,跨模态预训练新进展
作者 | 李根、段楠、周明来源 | 微软研究院AI头条(ID:MSRAsia)【导读】机器推理要求利用已有的知识和推断技术对未见过的输入信息作出判断,在自然语言处理领域中非常重要。本文将介绍微软亚洲研究院在跨模态预训练领域的研究进展。近年来&…

[LeetCode]:94:Binary Tree Inorder Traversal
题目: Given a binary tree, return the inorder traversal of its nodes values. For example:Given binary tree {1,#,2,3}, 1\2/3return [1,3,2]. 代码: public class Solution {public static ArrayList<Integer> listResult new ArrayList&l…
腾讯 AI 2019这一年
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送近日,腾讯AI实验室总结了 2019 年其取得重大进展的两大研究方向,推动实现的行业应用以及前沿研究探索方面的成果。一、两大难题攻坚:通用人工智能与数字人用…
跨平台PHP调试器设计及使用方法——探索和设计
在《跨平台PHP调试器设计及使用方法——立项》一文中,我确定了使用xdebug作为调试器插件部分的基础组件。xdebug提供了一个远程调试的功能(相关资料可以详见https://xdebug.org/docs/remote),我们这个项目便是基于这个功能实现的。…

Ubuntu下允许Root用户直接登录图形界面
ubuntu root是默认禁用了,不允许用root登陆,所以先要设置root密码。 执行:sudo passwd root 接着输入密码和root密码,重复密码。再重新启动就可以用root登陆。 另外,默认情况下是不允许用root帐号直接登陆图形界面的。…

携程App for Apple Watch探索
在Apple Watch发布之后,很多App都针对它设计了相应的版本。旅行作为与Apple Watch时间管理特性契合度较高的场景,同时携程旅行作为国内领先的OTA行业App,也成为了首批适配Apple Watch并荣登Apple官网和App Store推荐的应用之一。InfoQ就App f…
跨平台PHP调试器设计及使用方法——通信
首先引用《跨平台PHP调试器设计及使用方法——探索和设计》中的结构图(转载请指明出于breaksoftware的csdn博客) 本文要介绍的是我们逻辑和pydbgp通信的实现(图中红框内内容)。 设计通信之前,我需要先设计一种通信协议…

MVP模式的相关知识
MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Mod…
“数学不行,还能干点啥?”面试官+CTO:干啥都费劲!
关于数学与程序员的“暧昧”关系,先看看网友的看法:同时编程圈也流传着一个段子:一流程序员靠数学,二流程序员靠算法,末端程序员靠百度,低端看高端就是黑魔法。想一想,我们日常学习、求职、工作…

CentOS7 yum 源的配置与使用
YUM:Yellowdog Updater Modified Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的Shell前端软件包管理器。基于RPM包管理,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖…

跨平台PHP调试器设计及使用方法——协议解析
在《跨平台PHP调试器设计及使用方法——探索和设计》一文中,我介绍了将使用pydbgp作为和Xdebug的通信库,并让pydbgp以(孙)子进程的方式存在。《跨平台PHP调试器设计及使用方法——通信》解决了和pydbgp通信的问题,本文…

测试客户端发图图
转载于:https://blog.51cto.com/ericsong/116942
搜狐、美团、小米都在用的Apache Doris有什么好? | BDTC 2019
【导读】12 月 5-7 日,由中国计算机学会主办,CCF 大数据专家委员会承办,CSDN、中科天玑协办的中国大数据技术大会(BDTC 2019)在北京长城饭店隆重举行。100 顶尖技术专家、1000 大数据从业者齐聚于此,以“大…

cacti邮件告警设置
功能说明对指定流量图形(指定接口)设置最高或最低流量阀值,当流量出现异常偏高或偏低触发阀值,系统自动将异常信息以邮件形式通知指定收件人。如果收件人邮箱是139邮箱,还可以增设短信通知功能。设置前准备设置该功能之…
跨平台PHP调试器设计及使用方法——高阶封装
在《跨平台PHP调试器设计及使用方法——协议解析》一文中介绍了如何将pydbgp返回的数据转换成我们需要的数据。我们使用该问中的接口已经可以构建一个简单的调试器。但是由于pydbgp存在的一些问题,以及调试器需要的一些高级功能,我们还需要对这些接口进行…

Oracle的口令文件(passwordfile)的讲解(摘录)
初学oracle,很多概念迷糊,今天看到这文章,让我有一个比较清晰的认识。转载[url]http://www.itpub.net/viewthread.php?tid906008&extra&page1[/url]1、os认证oracle安装之后默认情况下是启用了os认证的,这里提到的os认证…
如何优雅地使用pdpipe与Pandas构建管道?
作者 | Tirthajyoti Sarkar译者 | 清儿爸编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100) 【导读】Pandas 是 Python 生态系统中的一个了不起的库,用于数据分析和机器学习。它在 Excel/CSV 文件和 SQL 表所在的数据世界与 Scikit-learn 或 Te…

第 十 天 : 添 加 硬 盘 和 分 区 挂 载 等
小Q:狼若回头,必有缘由,不是报恩,就是***; 事不三思必有败,人能百忍则无忧。今天的进度虽然慢了,但是学习状态还是一如往常,只不过今天遇到了不少新的知识点,需要好好想想…
从4个月到7天,Netflix开源Python框架Metaflow有何提升性能的魔法?
作者 | Rupert Thomas译者 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导语】Metaflow 是由 Netflix 开发,用在数据科学领域的 Python框架,于 2019 年 12 月正式对外开源。据介绍,Metaflow 解决…
SOA标准发展混乱 国内业务缺少经验
近年来,SOA已经成为国际及我国信息技术领域的重大热点之一。从2005年至今,SOA逐渐成为影响中国IT系统构建的主导思想。从2006年开始,SOA的建设方法已在我国部分行业信息化项目中开始得以越来越广泛的应用。 但热潮背后, SOA概念在…
跨平台PHP调试器设计及使用方法——界面设计和实现
一个优秀的交互设计往往会影响一个产品的命运。在设计这款调试器时,我一直在构思这款调试器该长什么样子。简单、好用是我设计的原则,于是在《跨平台PHP调试器设计及使用方法——立项》一文中,我给出了一个Demo。之后实现的效果也与之变化并不…

AJAX安全-Session做Token
个人思路,请大神看到了指点 个人理解token是防止扫号机或者恶意注册、恶意发表灌水,有些JS写的token算法,也会被抓出来被利用,个人感觉还是用会过期的Session做token更好,服务器存储,加载到客户端页面&…
跨平台PHP调试器设计及使用方法——使用
经过之前六篇博文的分析和介绍,大家应该对这套调试器有个初步的认识。本文我将讲解它的使用方法。(转载请指明出于breaksoftware的csdn博客) 上图是该软件界面的布局,我们之后的讲解也将围绕着这些功能展开。 文件夹管理 在查看一…