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

news2025/1/12 3:42:03

 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.coloradmin.cn/o/1618698.html

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

相关文章

PHP-001、PHP学习之PhpStorm+PhpStudy环境安装

一、说明 由于当前需要&#xff0c;暂时停止学习python&#xff0c;当然有时间继续&#xff0c;转为php&#xff0c;听说php开发网站、小程序等运行效率更高&#xff0c;朋友那边再做这个&#xff0c;准备学习一下&#xff0c;和朋友们一起来吧&#xff0c;就这开发环境安装&a…

李沐60_机器翻译数据集——自学笔记

!pip install d2limport os import torch from d2l import torch as d2l下载和预处理数据集 在这个将英语翻译成法语的机器翻译问题中&#xff0c; 英语是源语言&#xff08;source language&#xff09;&#xff0c; 法语是目标语言&#xff08;target language&#xff09;。…

求职招聘小程序源码系统 全开源源代码:找工作+招人才功能强大 带完整的安装代码包以及搭建教程

互联网的深入发展&#xff0c;求职招聘已经不再是传统的线下模式所能满足的。越来越多的企业和求职者开始倾向于线上招聘&#xff0c;寻找更加便捷、高效的求职招聘方式。因此&#xff0c;我们结合市场需求和技术发展趋势&#xff0c;推出了这款求职招聘小程序源码系统。 该系…

VNISEdit 制作安装包

1. 环境依赖 1.1. NSIS 下载 下载地址&#xff1a;https://nsis.sourceforge.io/Download 1.2. VNISEdit 下载 下载地址1&#xff1a;https://sourceforge.net/projects/hmne/ 下载 exe 安装。 下载地址2&#xff1a;https://hmne.sourceforge.net/ 可以下载 exe 安装。也…

OurBMC大咖说|第4期:基于飞腾腾珑E2000的国产化BMC固件开发简介

栏目介绍&#xff1a;"OurBMC大咖说" 是由 OurBMC 社区精心策划的线上讲座栏目&#xff0c;邀请 BMC 相关领域大咖共同探讨 BMC 全栈技术的发展趋势、挑战和机遇。无论你是初学者还是资深从业者&#xff0c;"OurBMC大咖说" 都将为你提供一个宝贵的学习和交…

如何确定IP地址的地理位置

IP地址的地理位置确定是一个复杂而精细的过程&#xff0c;它结合了多种技术与方法来推断或确定设备在网络中的大致物理位置。以下是对IP地址地理位置确定过程的详细解释&#xff1a; 首先&#xff0c;我们要理解IP地址本身并不能直接反映物理位置信息。IP地址主要是用于在网络中…

路由引入,过滤实验

实验拓补图 实验目的&#xff1a; 1、按照图示配置 IP 地址&#xff0c;R1&#xff0c;R3&#xff0c;R4 loopback口模拟业务网段 2、R1 和 R2 运行 RIPv2,R2&#xff0c;R3和R4运行 OSPF&#xff0c;各自协议内部互通 3、在 RIP 和 oSPF 间配置双向路由引入,要求除 R4 上的…

计算机java项目|springboot档案管理系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、Python项目、前端项目、人工智能与大数据、简…

工业级扫描式避障型激光雷达选型指南

工业级扫描式激光避障型传感器选型指南 在工业自动化领域&#xff0c;扫描式激光避障型传感器已成为不可或缺的关键组件。其高精度、高可靠性以及快速响应能力&#xff0c;使得机器人在复杂环境中能够安全、高效地执行任务。然而&#xff0c;面对市场上众多的传感器产品&#…

【S32DS RTD实战】-1.5-S32DS使用Post-Build调用第三方插件-自动对生成的s19,Hex,Bin文件二次编辑

<--返回「Autosar_MCAL高阶配置」专栏主页--> 案例背景&#xff1a; 在《【S32DS RTD实战】-1.3-S32K3工程生成S19&#xff0c;BIN&#xff0c;Hex文件&#xff0c;以及Post-build steps的妙用_s32ds如何生成s19或hex文件-CSDN博客https://blog.csdn.net/qfmzhu/articl…

RTU遥测终端为城市排水安全保驾护航!

近年来&#xff0c;全球气候变迁与城市化进程不断加速&#xff0c;导致强降雨事件频发&#xff0c;道路低洼地带、下穿式立交桥和隧道等区域在暴雨中常易积水&#xff0c;严重阻碍了人民的出行&#xff0c;甚至危及生命与财产安全。而传统的排水管网管理方式已难以适应现代城市…

【大模型系列】预训练

数据 数据预处理 预处理流程&#xff1a; 原始语料库—>质量过滤&#xff08;语种过滤、统计过滤、关键词过滤、分类器过滤&#xff09;—>敏感内容过滤&#xff08;有毒内容、隐私内容PII&#xff09;—>数据去重&#xff08;句子级别、文档级别、数据集级别&#…

【python】Python学生信息管理系统(源码+报告+本地存储)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

stack、queue(priority_queue)的模拟实现和deque的简单介绍

stack和queue(priority_queue) 1. 容器适配器 适配器(Adapter)&#xff1a;一种用来修饰容器(Containers)或仿函数(Functors)或迭代器(Iterator)接口的东西。 适配器是一种设计模式&#xff0c;该模式将一个类的接口转换成客户希望的另外一个接口。 现实中拿插座来说&#xf…

Linux:Win10平台上,用VMware安装Centos7.x及系统初始化关键的相关配置(分步骤操作,详细,一篇足以)

VMware安装Centos7.x镜像的详细步骤&#xff1a;VMWare安装Centos系统&#xff08;无桌面模式&#xff09; 我这里是为了安装Hadoop集群&#xff0c;所以&#xff0c;以下这些步骤是必须进行的 如果你是学习Linux&#xff0c;可以跳过非必须的那些配置项 我安装的版本是&…

水牛社靠谱吗,水牛社可以当做副业来做吗?

水牛社这个平台是否靠谱&#xff0c;能否作为副业的选择&#xff0c;一直是网友们热议的话题。实际上&#xff0c;水牛社是一个集合了众多网上赚钱活动任务和提供资源项目教程的综合性平台&#xff0c;它并非只局限于某一特定的项目&#xff0c;而是展现出多样化的特点。随着网…

总结Java中的synchronized

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 目录 总结*synchronized**初识synchronized*使用synchronizedsynchronized的特性(1)可重入性(2)自适应过程(3)锁消除(4)非公平锁(5)互斥锁 总结synchronized 初识synchronized 通过一个线程不安…

光明与速度:AI网络中GPU与光模块的协奏曲

&#x1f3b6;在人工智能&#xff08;AI&#xff09;的世界里&#xff0c;GPU和光模块是实现高速计算和数据传输的关键。它们如同一场精心编排的交响乐&#xff0c;每个部分都不可或缺&#xff0c;共同创造出美妙的和谐。&#x1f3bc; GPU&#xff1a;AI网络的心脏&#x1f4…

Python-GEE遥感云大数据分析、管理与可视化

原文链接&#xff1a;Python-GEE遥感云大数据分析、管理与可视化https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247601238&idx2&sn6b0557cf61451eaff65f025d648da869&chksmfa820db1cdf584a76de953b96519704177e6206d4ecd47a2f2fabbcac2f7ea619b0bce184…

MATLAB中roots函数用法

目录 语法 说明 示例 二次多项式的根 四次多项式的根 提示 roots函数的功能是求解多项式的根。 语法 r roots(p) 说明 r roots(p) 以列向量的形式返回 p 表示的多项式的根。输入 p 是一个包含 n1 多项式系数的向量&#xff0c;以 xn 系数开头。0 系数表示方程中不存…