朴素、Select、Poll和Epoll网络编程模型实现和分析——Poll、Epoll模型处理长连接性能比较_poll什么时候比epoll快-程序员宅基地

技术标签: 网络编程模型的分析、实现和对比  

        在《朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较》一文中,我们分析了各种模型在处理短连接时的能力。本文我们将讨论处理长连接时各个模型的性能。(转载请指明出于breaksoftware的csdn博客)

        我们可以想象下场景,如果我们使用朴素模型来处理长连接,则需要引入多线程来处理:主线程接收接入的Socket,子线程处理一个个Socket的读写。因为长连接需要客户端和服务器之间维系一段时间,所以服务器子线程要一直同步等待socket的改变。如果socket长时间没有变化,那么这个子线程就将长期处于闲置状态,这无疑是对资源的一种浪费。然而此时Select、Poll和Epoll模型就能很好的解决这个问题,因为它是异步事件通知模式,所以不需要大量的线程同步等待,可以很好的利用线程资源。

        因为我不想引入多线程协助处理,而朴素模型在处理长连接的情况下需要多线程协助,所以我没有将朴素模型列入之后的对长连接支持的改造。还有我也不打算对Select模型代码进行改造,因为我们之前已经分析过,Select模型只能处理一定数量的长连接,所以在高并发的场景下,它也没法使用。于是我们需要改造的是Poll和Epoll模型的代码,其实修改非常简单,我们只要将之前写完回包操作之后的关闭连接给去掉即可。

        下一步,我们要对客户端进行改造。为了让客户端足够高效的利用线程资源,我们将客户端也改成Epoll模型。

void* send_data(void* arg) {
	int wait_time;
	int epfd, nfds;
	int client_sock;
	struct epoll_event ev, events[SOCKET_LIST_COUNT];
	int in_events, out_events;
	int index;

	wait_time = *(int*)arg;
	in_events = EPOLLIN | EPOLLET;
	out_events = EPOLLOUT | EPOLLET;
	
	epfd = epoll_create1(0);

	for (index = 0; index < 100; index++) {
		client_sock = make_client_socket();
		connect_server(client_sock);
		set_nonblock(client_sock);
		request_add(1);
		
		ev.data.fd = client_sock;
		ev.events = in_events;
		epoll_ctl(epfd, EPOLL_CTL_ADD, client_sock, &ev);
		
		client_write(client_sock);
		ev.events = in_events;
		epoll_ctl(epfd, EPOLL_CTL_MOD, client_sock, &ev);
	}	

	while (1) {
		nfds = epoll_wait(epfd, events, sizeof(events), 500);
		usleep(wait_time);
		for (index = 0; index < nfds; ++index) {
			int fd = events[index].data.fd;
			if (events[index].events & EPOLLIN) {
				if (0 != client_read(fd)) {
					close(fd);
					epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
				}
				else {
					events[index].events = out_events;
					epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &events[index]);
				}
			}
			else if (events[index].events & EPOLLOUT) {
				client_write(fd);
				events[index].events = in_events;
				epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &events[index]);
			}
		}
	}
	close(epfd);
}

        我们只对线程函数进行修改。让一个线程新建100个socket去连接服务器,并使用Epoll模型去管理这些socket。

        由于我的环境默认只能同时处理1024个连接,所以我使用ulimit -n 3000指令修改了该值,以让我们服务器可以同时处理3000个连接(实际上不到3000个,因为系统还要占用几个)。

        最后在3个终端中使用./epoll_client 10 10指令启动客户端,让客户端启动30个线程,共新建3000个长连接。这3000个长连接每隔10微秒向服务器发送和接收一次数据。我们看下Poll模型的稳定时的表现

        平均每秒处理27222次“读和写”操作。我们再看下EPoll模型的表现

        平均每秒处理18876次“读和写”操作。

        我们非常惊讶的发现Epoll模型竟然比Poll模型差!我们使用varlgrind对两种模型进行分析

        Poll模型的main函数自身耗时占比仅为12.11%。其主要是读写操作的占用。而其执行循环的次数是 10 113 131次,有效循环是8 374 693次,有效率是82.2%。这个比例还是不错的。

        我们再看Epoll模型的统计结果

        Epoll模型的main函数自身占用26.56%,这个比例是Poll模型的两倍。其中循环次数和有效循环次数一致,故有效率是100%。

        通过上面的对比,我们可以推定就是main函数自身的耗时影响了Epoll模型的效率。

        和《朴素、Select、Poll和Epoll网络编程模型实现和分析——模型比较》中对Poll和Epoll模型的性能统计分析,我们发现Poll模型的main函数自身耗时占比有明显的变化,前文是46.93%,本文是12.11%。而Epoll模型的main函数自身耗时占比则比较稳定,前文是25.7%,本文是26.56%。

        我们再看下CPU和内存的情况

        可以发现当前测试环境下两个模型的CPU和内存占用情况是相差不大的。

        经过以上分析,我们可以发现在处理长连接时,如果同时连接数量不是很大,且长连接通信频繁时,Poll模型的效率是比Epoll高的。

        那么什么时候Epoll效率最高呢?对比Poll和Epoll模型,我们发现Poll模型中有效循环的比例会随着连接数量上涨、通信频度下降而下降。于是我们模拟大量长连接,通信频度不高的场景。

        为了能支持高并发,我们需要对我们的系统设置进行一些修改。我的测试环境是Ubuntu Server 14,网上有一篇博文《Ubuntu 12 ulimit 系统最大打开文件个数 设置》,我按此博文介绍将我的环境下的最大连接数改成了40960。这一步非常必要。
        我们使用,/epoll_client 200 1000000指令启动20个线程,供建立20000个连接,各个连接每一秒钟发送一次请求。

        我们看下Poll模型的表现

        Poll模型平均每秒完成6665次“读和写”操作,且CPU占用率高达65%。

        再看下Epoll模型的表现

        Epoll模型平均每秒完成6871次“读和写”操作,而CPU占用率只有8.6%。

        上述现象说明在大量长连接、不频繁通信的情况下,Epoll模型比Poll模型在CPU消耗上要优秀非常多。

        同样我们使用varlgrind分析这种场景下Poll模型和Epoll模型的耗时情况

         首先看Poll模型

        Poll模型的main函数自身耗时占了64.65%。总循环次数445 973 878,有效循环次数2 135 891,有效率0.48%。

        再看看Epoll模型的统计结果

  

        Epolll模型的main函数自身耗时还是稳定在26.57%。总循环次数和有效循环次数一致,故有效率100%。

        网上还有很多关于Poll模型和Epoll模型在内核源码级别的对比,并指出Epoll模型的源码是多么的高效。但是使用varlgrind工具测试发现,其主要的性能差距是在无效循环的比例上。而内核源码导致的性能进步却没有明显体现。我们以strlen函数为参考进行对比就可以发现上述观点(可以认为不同程序里对相同内容空间进行strlen操作耗时是一样)。

        Poll模型的strlen函数和poll函数的耗时占比是1.21:0.01=121。而Epoll模型中则是9.38:(2.36+0.23)=3.63。

        经过这一系列博文的分析,我们可以大致掌握朴素、Select、Poll和Epoll模型的编程方法,同时也对不同场景下选择什么模型有了一定的认识。

        最后附上代码链接:http://pan.baidu.com/s/1bTP7MQ 密码:0mc9

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/breaksoftware/article/details/51675103

智能推荐

FTP命令字和返回码_ftp 登录返回230-程序员宅基地

文章浏览阅读3.5k次,点赞2次,收藏13次。为了从FTP服务器下载文件,需要要实现一个简单的FTP客户端。FTP(文件传输协议) 是 TCP/IP 协议组中的应用层协议。FTP协议使用字符串格式命令字,每条命令都是一行字符串,以“\r\n”结尾。客户端发送格式是:命令+空格+参数+"\r\n"的格式服务器返回格式是以:状态码+空格+提示字符串+"\r\n"的格式,代码只要解析状态码就可以了。读写文件需要登陆服务器,特殊用..._ftp 登录返回230

centos7安装rabbitmq3.6.5_centos7 安装rabbitmq3.6.5-程序员宅基地

文章浏览阅读648次。前提:systemctl stop firewalld 关闭防火墙关闭selinux查看getenforce临时关闭setenforce 0永久关闭sed-i'/SELINUX/s/enforcing/disabled/'/etc/selinux/configselinux的三种模式enforcing:强制模式,SELinux 运作中,且已经正确的开始限制..._centos7 安装rabbitmq3.6.5

idea导入android工程,idea怎样导入Android studio 项目?-程序员宅基地

文章浏览阅读5.8k次。满意答案s55f2avsx2017.09.05采纳率:46%等级:12已帮助:5646人新版Android Studio/IntelliJ IDEA可以直接导入eclipse项目,不再推荐使用eclipse导出gradle的方式2启动Android Studio/IntelliJ IDEA,选择 import project3选择eclipse 项目4选择 create project f..._android studio 项目导入idea 看不懂安卓项目

浅谈AI大模型技术:概念、发展和应用_ai大模型应用开发-程序员宅基地

文章浏览阅读860次,点赞2次,收藏6次。AI大模型技术已经在自然语言处理、计算机视觉、多模态交互等领域取得了显著的进展和成果,同时也引发了一系列新的挑战和问题,如数据质量、计算效率、知识可解释性、安全可靠性等。城市运维涉及到多个方面,如交通管理、环境监测、公共安全、社会治理等,它们需要处理和分析大量的多模态数据,如图像、视频、语音、文本等,并根据不同的场景和需求,提供合适的决策和响应。知识搜索有多种形式,如语义搜索、对话搜索、图像搜索、视频搜索等,它们可以根据用户的输入和意图,从海量的数据源中检索出最相关的信息,并以友好的方式呈现给用户。_ai大模型应用开发

非常详细的阻抗测试基础知识_阻抗实部和虚部-程序员宅基地

文章浏览阅读8.2k次,点赞12次,收藏121次。为什么要测量阻抗呢?阻抗能代表什么?阻抗测量的注意事项... ...很多人可能会带着一系列的问题来阅读本文。不管是数字电路工程师还是射频工程师,都在关注各类器件的阻抗,本文非常值得一读。全文13000多字,认真读完大概需要2小时。一、阻抗测试基本概念阻抗定义:阻抗是元器件或电路对周期的交流信号的总的反作用。AC 交流测试信号 (幅度和频率)。包括实部和虚部。​图1 阻抗的定义阻抗是评测电路、元件以及制作元件材料的重要参数。那么什么是阻抗呢?让我们先来看一下阻抗的定义。首先阻抗是一个矢量。通常,阻抗是_阻抗实部和虚部

小学生python游戏编程arcade----基本知识1_arcade语言 like-程序员宅基地

文章浏览阅读955次。前面章节分享试用了pyzero,pygame但随着想增加更丰富的游戏内容,好多还要进行自己编写类,从今天开始解绍一个新的python游戏库arcade模块。通过此次的《连连看》游戏实现,让我对swing的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。_arcade语言 like

随便推点

【增强版短视频去水印源码】去水印微信小程序+去水印软件源码_去水印机要增强版-程序员宅基地

文章浏览阅读1.1k次。源码简介与安装说明:2021增强版短视频去水印源码 去水印微信小程序源码网站 去水印软件源码安装环境(需要材料):备案域名–服务器安装宝塔-安装 Nginx 或者 Apachephp5.6 以上-安装 sg11 插件小程序已自带解析接口,支持全网主流短视频平台,搭建好了就能用注:接口是公益的,那么多人用解析慢是肯定的,前段和后端源码已经打包,上传服务器之后在配置文件修改数据库密码。然后输入自己的域名,进入后台,创建小程序,输入自己的小程序配置即可安装说明:上传源码,修改data/_去水印机要增强版

verilog进阶语法-触发器原语_fdre #(.init(1'b0) // initial value of register (1-程序员宅基地

文章浏览阅读557次。1. 触发器是FPGA存储数据的基本单元2. 触发器作为时序逻辑的基本元件,官方提供了丰富的配置方式,以适应各种可能的应用场景。_fdre #(.init(1'b0) // initial value of register (1'b0 or 1'b1) ) fdce_osc (

嵌入式面试/笔试C相关总结_嵌入式面试笔试c语言知识点-程序员宅基地

文章浏览阅读560次。本该是不同编译器结果不同,但是尝试了g++ msvc都是先计算c,再计算b,最后得到a+b+c是经过赋值以后的b和c参与计算而不是6。由上表可知,将q复制到p数组可以表示为:*p++=*q++,*优先级高,先取到对应q数组的值,然后两个++都是在后面,该行运算完后执行++。在电脑端编译完后会分为text data bss三种,其中text为可执行程序,data为初始化过的ro+rw变量,bss为未初始化或初始化为0变量。_嵌入式面试笔试c语言知识点

57 Things I've Learned Founding 3 Tech Companies_mature-程序员宅基地

文章浏览阅读2.3k次。57 Things I've Learned Founding 3 Tech CompaniesJason Goldberg, Betashop | Oct. 29, 2010, 1:29 PMI’ve been founding andhelping run techn_mature

一个脚本搞定文件合并去重,大数据处理,可以合并几个G以上的文件_python 超大文本合并-程序员宅基地

文章浏览阅读1.9k次。问题:先讲下需求,有若干个文本文件(txt或者csv文件等),每行代表一条数据,现在希望能合并成 1 个文本文件,且需要去除重复行。分析:一向奉行简单原则,如无必要,绝不复杂。如果数据量不大,那么如下两条命令就可以搞定合并:cat a.txt >> new.txtcat b.txt >> new.txt……去重:cat new...._python 超大文本合并

支付宝小程序iOS端过渡页DFLoadingPageRootController分析_类似支付宝页面过度加载页-程序员宅基地

文章浏览阅读489次。这个过渡页是第一次打开小程序展示的,点击某个小程序前把手机的开发者->network link conditioner->enable & very bad network 就会在停在此页。比如《支付宝运动》这个小程序先看这个类的.h可以看到它继承于DTViewController点击左上角返回的方法- (void)back;#import "DTViewController.h"#import "APBaseLoadingV..._类似支付宝页面过度加载页

推荐文章

热门文章

相关标签