【Linux高性能服务器编程】两种高性能并发模式剖析——半同步/半异步模式

 16b9d0dfc990426e968798e2f5a7628b.png

hello !大家好呀! 欢迎大家来到我的Linux高性能服务器编程系列之两种高性能并发模式介绍,在这篇文章中,你将会学习到高效的创建自己的高性能服务器,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!!

希望这篇文章能对你有所帮助9fe07955741149f3aabeb4f503cab15a.png,大家要是觉得我写的不错的话,那就点点免费的小爱心吧!1a2b6b564fe64bee9090c1ca15a449e3.png(注:这章对于高性能服务器的架构非常重要哟!!!)

03d6d5d7168e4ccb946ff0532d6eb8b9.gif         

导言:

并发编程的目的是让程序“同时”执行多个任务。如果程序是计算密集型的,并发编程并没有优势,反而由于任务的切换使效率降低。但如果程序是I/O 密集型的,比如经常读写文件,访问数据库等,则情况就不同了。由于I/O 操作的速度远没有CPU的计算速度快,所以让程序阻塞于I/O 操作将浪费大量的CPU时间。如果程序有多个执行线程,则当前被I/O操作所阻塞的执行线程可主动放弃CPU(或由操作系统来调度),并将执行权转移到其他线程。这样一来,CPU 就可以用来做更加有意义的事情(除非所有线程都同时被I/O 操作所阻塞),而不是等待I/O操作完成,因此CPU的利用率显著提升。

 

目录

 一.半同步/半异步模式

 1.1 什么是同步/异步

1.2 半同步/半异步 

 1.3 半同步/半反应堆模式(变体)

1.4 更高效的半同步/半异步模式

 1.5 实例代码


 

 一.半同步/半异步模式

 1.1 什么是同步/异步

 首先,对于I/O模型中的同步和异步,意思是区分内核向应用程序通知的是何种I/O事件(是就绪事件还是完成事件),以及让谁来完成任务(是应用程序还是内核)。而在并发编程中,指程序按照顺序还是需要按照程序执行的需要由系统事件来驱动,常见的系统事件有:中断,信号。

如下图:

按照同步方式运行的线程称为同步线程,按照异步方式运行的线程称为异步线程。显然,异步线程的执行效率高,实时性强,这是很多嵌入式程序采用的模型。但编写以异步方式执行的程序相对复杂,难于调试和扩展,而且不适合于大量的并发。而同步线程则相反,它虽然效率相对较低,实时性较差,但逻辑简单。因此,对于像服务器这种既要求较好的实时性,又要求能同时处理多个客户请求的应用程序,我们就应该同时使用同步线程和异步线程来实现,即采用半同步/半异步模式来实现。

 

1.2 半同步/半异步 

在这个模式中,同步线程用于处理客户逻辑,异步线程用于处理I/O事件,异步线程监听到客户请求后,将其封装为请求对象并且插入请求队列中,请求队列将通知某个工作在同步模式的工作线程来读取并且处理该对象,线程选择使用Round Robin算法,也可以通过条件变量和信号量来实现,具体工作流程图如图所示:

 

 1.3 半同步/半反应堆模式(变体)

异步线程只有一个,由主线程来充当。它负责监听所有socket上的事件。如果监听socket 上有可读事件发生,即有新的连接请求到来,主线程就接受之以得到新的连接socket,然后往epoll内核事件表中注册该socket上的读写事件。如果连接socket 上有读写事件发生,即有新的客户请求到来或有数据要发送至客户端,主线程就将该连接 socket插入请求队列中。所有工作线程都睡眠在请求队列上,当有任务到来时,它们将通过竞争(比如申请互斥锁)获得任务的接管权。这种竞争机制使得只有空闲的工作线程才有机会来处理新任务,这是很合理的。

如图:

其中主线程插入请求队列中的任务是就绪的连接socket , 这说明半同步/半反应堆模式采用的事件处理模式是Reactor模式:它要求工作线程自己从socket 上读取客户请求和往socket写入服务器应答。

这就是该模式的名称中“half-reactive”的含义。实际上,半同步/半反应堆模式也可以使用模拟的Proactor事件处理模式,即由主线程来完成数据的读写。在这种情况下,主线程一般会将应用程序数据、任务类型等信息封装为一个任务对象,然后将其(或者指向该任务对象的一个指针)插入请求队列。工作线程从请求队列中取得任务对象之后,即可直接处理之,而无须执行读写操作。

半同步/半反应堆模式存在如下缺点:

 1) 主线程和工作线程共享请求队列。主线程往请求队列中添加任务,或者工作线程从请求队列中取出任务,都需要对请求队列加锁保护,从而白白耗费CPU 时间。  

 2)    每个工作线程在同一时间只能处理一个客户请求。如果客户数量较多,而工作线程较少,则请求队列中将堆积很多任务对象,客户端的响应速度将越来越慢。如果通过增加工作线程来解决这一问题,则工作线程的切换也将耗费大量CPU 时间。

 

1.4 更高效的半同步/半异步模式

     主线程只管理监听socket, 连接socket由工作线程来管理,当有新的连接到来时,主线程就接受之并将新返回的连接socket 派发给某个工作线程,此后该新 socket上的任何I/O操作都由被选中的工作线程来处理,直到客户关闭连接。

主线程向工作线程派发socket 的最简单的方式,是往它和工作线程之间的管道里写数据。

工作线程检测到管道上有数据可读时,就分析是否是一个新的客户连接请求到来。如果是,则把该新 socket上的读写事件注册到自己的epoll内核事件表中。  

每个线程(主线程和工作线程)都维持自己的事件循环,它们各自独立地监听不同的事件。因此,在这种高效的半同步/半异步模式中,每个线程都工作在异步模式,所以它并非严格意义上的半同步/半异步模式。
 

 1.5 实例代码

异步线程逻辑处理:


// 事件处理函数
void *handle_connection(void *socket_desc) {int sock = *(int*)socket_desc;char *message;int len;// 接收客户端数据while((len = read(sock, message, 1024)) > 0) {printf("收到数据:%s\n", message);// 发送响应write(sock, "Hello, Client!", 14);memset(message, 0, 1024);}// 关闭套接字close(sock);return 0;
}

同步线程监听请求和分配任务给异步线程:

// 循环处理事件while(1) {activity = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);if ((activity < 0) && (errno != EINTR)) {printf("select error");return -1;}if (FD_ISSET(sock, &readfds)) {// 有新的客户端连接newsock = accept(sock, (struct sockaddr *)&cli_addr, (socklen_t*)&clilen);printf("新的客户端连接:%s\n", inet_ntoa(cli_addr.sin_addr));client_sockets[i] = newsock;FD_SET(newsock, &readfds);}for (i = 0; i < MAX_CLIENTS; i++) {if (FD_ISSET(client_sockets[i], &readfds)) {// 处理客户端数据new_sock = malloc(1);*new_sock = client_sockets[i];if (pthread_create(&thread_id, NULL, handle_connection, (void*)new_sock) < 0)return -1;}pthread_detach(thread_id);free(new_sock);FD_CLR(client_sockets[i], &readfds);}}}

 

   好啦!到这里这篇文章就结束啦,关于实例代码中我写了很多注释,如果大家还有不懂得,可以评论区或者私信我都可以哦4d7d9707063b4d9c90ac2bca034b5705.png!! 感谢大家的阅读,我还会持续创造网络编程相关内容的,记得点点小爱心和关注哟!2cd0d6ee4ef84605933ed7c04d71cfef.jpeg      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/827641.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《HCIP-openEuler实验指导手册》1.4 Apache MPM工作模式调整

MPM介绍 二、配置步骤 查看MPM当前工作模式 方法一&#xff1a; httpd -M | grep mpm方法二&#xff1a; 浏览器访问&#xff1a;http://IP:端口/server-status 方法三&#xff1a; cat /etc/httpd/conf.modules.d/00-mpm.conf查看 LoadModule mpm_event_module modules/mo…

Iterator 迭代器

意图 提供一个方法顺序访问一个聚合对象中的各个元素&#xff0c;且不需要暴漏该对象的内部表示。 结构 Iterator&#xff08;迭代器&#xff09;定义访问和遍历元素的接口。ConcreteIterator&#xff08;具体迭代器&#xff09;实现迭代器接口&#xff1b;对该聚合遍历是跟踪…

DSSM 模型技术介绍

转自&#xff1a;git 本文属于新闻推荐实战-召回阶段-DSSM召回模型。区别于策略召回&#xff0c;基于向量召回也是目前工业界常用的一种召回方法。这里我们将介绍一个比较经典的召回模型DSSM&#xff0c;希望读者可以快速掌握模型原理以及细节&#xff0c;同时可以了解具体的实…

Nacos原理简单介绍

注册中心原理 官网&#xff1a;Nacos 注册中心的设计原理 | Nacos nacos注册中心采用了 &#xff1a;pull &#xff08;客户端的轮询&#xff09;和push &#xff08;服务端主动push&#xff09;策略 客户端启动时会将当前服务的信息包含ip、端口号、服务名、集群名等信息封装…

电脑问题快速判断

电脑开机没有任何反应 检查电源 检查电源是否有问题或损坏&#xff0c;可以短接方法检测 板电源卡口对自己接第四或第五根线&#xff0c;若风扇匀速转动&#xff0c;电源无问题&#xff0c;若不转动或转一下停一下&#xff0c;电源有问题 检查内部连线 确保主板上的线插的…

2024新算法角蜥优化算法(HLOA)和经典灰狼优化器(GWO)进行无人机三维路径规划设计实验

简介&#xff1a; 2024新算法角蜥优化算法&#xff08;HLOA&#xff09;和经典灰狼优化器&#xff08;GWO&#xff09;进行无人机三维路径规划设计实验。 无人机三维路径规划的重要意义在于确保飞行安全、优化飞行路线以节省时间和能源消耗&#xff0c;并使无人机能够适应复杂…

手把手教你搭建鲜花团购小程序

随着互联网的快速发展&#xff0c;线上小程序商城已经成为了一种流行的电商模式。对于花店来说&#xff0c;开发线上小程序商城不仅可以扩大销售渠道&#xff0c;提高销售效率&#xff0c;还可以增加客户粘性&#xff0c;提升品牌形象。下面就以花店为例&#xff0c;教你怎么开…

OceanBase V4.2特性解析:用 Show Trace 快速定位数据库性能瓶颈

在数据库日常运维中&#xff0c;当遇到慢SQL问题时&#xff0c;若无法迅速查明原因&#xff0c;将极大地影响用户的使用感受&#xff0c;甚至可能引发业务或服务的中断。相较于单机数据库&#xff0c;分布式数据库系统因其涉及多个节点和多组件的协同工作&#xff0c;集群规模可…

DSP开发实战教程--EPWM模块的影子寄存器详细讲解原理和代码实例

EPWM模块影子寄存器的原理 在TI(Texas Instruments)的DSP28335中,EPWM(Enhanced Pulse Width Modulator)模块提供了高精度、高灵活性的PWM信号生成功能。为了能在不影响当前PWM波形输出的情况下预装载新的PWM参数(如周期、占空比等),EPWM模块引入了影子寄存器的概念。 …

STM32 ADC转换器

一、ADC简介 ADC&#xff08;Analog-Digital Converter&#xff0c;模拟-数字转换器&#xff09;&#xff0c;可以将引脚上连续变化的模拟量转换为内存中存储的数字量&#xff0c;建立模拟电路到数字电路的桥梁 模拟量&#xff1a;时间和幅值均连续的信号&#xff0c;例如&…

sklearn 笔记 metrics

1 分类 1.1 accuracy_score 分类准确率得分 在多标签分类中&#xff0c;此函数计算子集准确率&#xff1a;y_pred的标签集必须与 y_true 中的相应标签集完全匹配。 1.1.1 参数 y_true真实&#xff08;正确&#xff09;标签y_pred由分类器返回的预测标签normalize 默认为 Tr…

LLama的激活函数SwiGLU 解释

目录 Swish激活函数 1. Swish函数公式 LLaMA模型中的激活函数 1. SwiGLU激活函数 2. SwiGLU激活函数的表达式 3. SwiGLU激活函数的优势 Swish激活函数 Swish是一种激活函数&#xff0c;其计算公式如下&#xff1a; 1. Swish函数公式 Swish(x) x * sigmoid(x) 其中&am…

概率图模型在机器学习中的应用:贝叶斯网络与马尔可夫随机场

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

【重要】Heygen订阅指南和用法详解!让照片学说话?一张照片变演讲?Heygen订阅值得吗?

常见问题 Q&#xff1a;Heygen是什么&#xff1f;Heygen是什么玩意&#xff1f; A&#xff1a;Heygen是一款由AI视频工具,创作者只需要上传视频并选择要翻译的语言&#xff0c;该工具可实现自动翻译、调整音色、匹配嘴型。为了方便理解&#xff0c;笔者利用Heygen制作了一个AI视…

裤裤带你一起学C语言内存函数啦!

目录 1.memcpy的使用和模拟实现 2.memmove使用和模拟实现 3.memset函数的使用 4.memcmp函数的使用 内存函数在<string.h>库中&#xff0c;我们使用内存函数必须先引入<string.h>头文件 1.memcpy的使用和模拟实现 memcpy的函数原型如下&#xff1a; void * m…

Vue--》深入了解 VueUse 功能性工具集

今天博主为大家介绍一款实用性的插件名字叫做 VueUse &#xff0c;它是专门为 Vue.js 生态系统设计的功能性工具集合。其提供了许多可重用的功能函数&#xff0c;可以帮助开发者更轻松地构建 Vue.js 应用程序。其提供了大量的功能&#xff0c;包括状态管理、副作用管理、组合式…

【刷题】前缀和入门

送给大家一句话&#xff1a; 既然已经做出了选择&#xff0c;最好还是先假定自己是对的。焦虑未来和后悔过去&#xff0c;只经历一个就够了。 – 张寒寺 《不正常人类症候群》 ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ(≧∇≦)〃))≧∇)ノ彡☆ ☆ミヾ(∇≦((ヾ…

react引入iconfont的svg图标

react引入iconfont的svg图标 本文目录 react引入iconfont的svg图标普通图标通过link引入css组件内引入css使用 svg图标通过script引入js组件内引入js使用 通过封装组件自定义封装组件中调用 通过antd封装使用 普通图标 通过link引入css <link rel"stylesheet" h…

基于springboot实现在线考试系统设计【项目源码+论文说明】计算机毕业设计

基于springboot实现在线考试管理系统演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于JavaWeb技术的在线考试系统设计与实现的开发全过程。通过分析基于Java Web技术的在线考试系统设计与实现管理的不…

http 3.0 有哪些新特性

HTTP/3 是超文本传输协议&#xff08;HTTP&#xff09;的最新主要版本&#xff0c;其显著特点是放弃了传统的TCP作为传输层协议&#xff0c;转而采用基于UDP的QUIC&#xff08;Quick UDP Internet Connections&#xff09;协议。以下是HTTP/3利用QUIC实现高性能传输的关键特性&…