【muduo源码学习】one-loop-per-thread核心原理

在 TCP 网络编程中,这里我们特指在单机的环境下,主要关注两件事。第一,如何正确的处理TCP的连接和断开,以及正确处理数据的收发;在错综复杂的网络环境中,这并非易事,涉及很多细节。第二,如何榨干机器的性能,即如何让单台机器在已有的硬件条件下处理尽可能多的连接请求;这需要设计一种高效的网络模型,这是本文讨论的主题,即在 muduo 网络库源码的学习基础上,总结和讨论。

下面进入本文的主题。

在TCP网络编程中,我们关注的核心是,在一个小的时间片段中,如何能够处理更多的并发连接。这主要可以从三个方面展开,而从一个服务端程序的性能指标来看,这三个方面分别为:响应时间、吞吐量和并发连接数。

  • 响应时间。响应时间是指请求发送到收到响应的时间。从程序本身来看,当收到客户端发来的请求时,TCP服务端需要能够立马处理,并将处理结果立马发送回客户端。更具体地,在面对短时间内有大量的请求到来时,TCP服务端要做尽可能地做到不阻塞在某个或某些请求处理上。这表现为,在错综复杂的网络环境中,数据的收发是不确定性,TCP服务端不能阻塞在socket上的读写上,这就要求socket是非阻塞的(nonblocking IO)。
  • 吞吐量。吞吐量是指单位时间内处理的请求数量。我们希望每个单机的TCP服务程序在单位时间内能够处理尽可能多的请求,这对于单核的CPU很容易就达到瓶颈,而对于多核的CPU,我们希望尽可能把每个核都跑满,使其处理充分多的请求,这就要求TCP服务程序具有很好的多线程网络模型,而下文中介绍的 one loop per thread 网络模型就可以很好的和多线程结合。
  • 并发连接数。并发连接数是指服务程序同时能够处理的连接数量。每个连接最少需要一定的内存资源,因此并发连接数会受计算机硬件的影响;此外每个连接至少需要一个socket文件描述符,而操作系统中的文件描述符数量是有限的,因此并发连接数会受到操作系统软件资源的影响。此外,从TCP服务程序本身来看,TCP服务程序可以同时保持很多连接,但在同一时刻处理这些已连接的请求的数量是少于总连接的数量的,同时TCP服务程序要需要处理源源不断带来的新连接,以及因为连接超时等原因关闭的连接,这就要求我们使用IO复用技术(IO multiplexing)。

小结一下,为降低响应时间,需要使用 nonblocking IO;为并发连接数尽可能大,需要使用 IO multiplexing;为了提高吞吐量,在程序上需要设计良好的多线程网络模型。下面就正式介绍 one loop per thread 网络模型,它是基于 nonblocking IO 和 IO multiplexing 的。

one loop per thread 网络模型,也称为 Reactor 模型。loop指事件循环,将文件描述符可读称为一个可读事件,将文件描述符可写称为一个可写事件,在TCP网络编程中,我们重点关注socket文件描述符上的读写事件。事件循环是指监控文件描述符上的读写事件,当有文件描述符变得可读或可写时,理解为发生了一次事件循环,即检测到一次事件发生。事件循环是依赖于 IO multiplexing 的。综上,one loop per thread 指每个线程中只有一个事件循环。

如下图所示,先来看下在单线程下,one loop per thread 网络模型长什么样子。
在这里插入图片描述

单线程下 one loop per thread 网络模型的TCP连接处理流程:

  • 服务端阻塞在 IO multiplexing 函数调用,等待客户端的请求到来。
  • 当客户端发送请求给服务端,IO multiplexing 函数检测到读事件,解除阻塞,然后获取产生读事件的 socket 文件描述符,从socket文件描述符上读取数据进行处理。在 IO multiplexing 函数中监控的 socket 文件描述有两类,一类是已连接的 socekt 文件描述符,一类是监听是否有新连接到来的 socket 文件描述符。
    • 对于监听socket上的读事件,调用 accept() 函数接收一个新的连接请求,并获取新连接的 socket 文件描述符,然后将其注册到 IO multiplexing 函数中。
    • 对于已连接的 socket 上的读事件,进行 read() --> 业务处理 --> write() 的处理流程。

one loop per thread 网络模型通过 nonblocking IO + IO multiplexing 可以很好的同时处理新连接和已连接,但存在的问题也显而易见,因为是单线程,你处理能力受限,且当已连接的处理比较耗时,新连接的响应时间就会受到影响。若已连接的处理比较耗时,比如是CPU密集计算任务,一种解决方案是,另起线程做CPU密集祭祀按任务,不让其影响IO线程,从而影响响应时间。当然这在单线程环境下都无从说起。

发挥 one loop per thread 网络模型能力的场合时多线程环境,通过将新连接的处理和已连接的处理分发到不同线程,来提高吞吐量。其本质是让已连接的处理不会影响新连接的处理。多线程下的 one loop per thread 网络模型如下图所示。
在这里插入图片描述

多线程 one loop per thread 网络模型下,每个线程中运行一个 loop,且每个线程最多运行一个 loop。在这个网络模型下,有一个主线程,有的博客中也称为主Reactor(Main Reactor)。主线程主要干两件事,第一,管理监听socket,当有新连接到来,即监听socket可读,调用 accept() 建立一个新连接;第二,获取新连接的 socket 后,将其分发到一个子线程中的 IO multiplexing 函数中,之后这个已连接 socket 上的读写事件主线程就不再负责,被分发到的子线程始终管理着这个已连接socket上的读写事件,直到这个连接关闭。

多线程的 one loop per thread 网络模型的优点:

  • 将新连接处理和已连接处理分离在不同的线程处理,兼顾服务程序的响应事件和吞吐量。
  • 监控 socket 上读写事件的线程是固定的,即不存在A线程监控读事件B线程监控写事件的情况,事件处理的流程简单。
  • 任务在线程之间的调配安全简单。在A线程调用B线程管理的socket上的回调函数,最终会转入B线程执行调用。(将在《muduo源码分析之Channel、EventLoop和Selector》的文章中详细介绍)

总结: 上述描述的 one loop per thread 网络模型主要涉及网络的IO,也即主要关心 socket 的读写事件,这是网络库关心的核心问题之一。因此,有时又将具有事件循环的线程称为IO线程。一个高效的网络库的核心工作是要能够处理足够大的并发量,即IO事件,当请求中涉及CPU密集计算任务时,不能让其在IO线程中占用过多的CPU资源,这样会影响到IO线程上的其他连接,一种解决办法是,为CPU密集计算任务开辟单独的线程或线程池,通过例如消息队列的形式将密集计算任务分发给这些线程, one loop per thread 模型可能很轻松进行这样的结合。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

过滤器和拦截器的样例

拦截器实例代码,加上之后必须登录才能访问其他功能接口 package com.itheima.interceptors;import com.itheima.utils.JwtUtil; import com.itheima.utils.ThreadLocalUtil; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSer…

数据结构和算法:贪心

贪心算法 贪心算法是一种常见的解决优化问题的算法,其基本思想是在问题的每个决策阶段,都选择当前看起来最优的选择,即贪心地做出局部最优的决策,以期获得全局最优解。 贪心算法和动态规划都常用于解决优化问题。它们之间存在一…

screen常用命令

screen是一个在Linux系统中常用的命令行终端模拟器&#xff0c;它允许用户在一个单一终端会话中管理多个终端窗口。以下是一些常用的screen命令 1、创建一个新的screen会话并命名 screen -S <name>2、control a d &#xff1a;分离&#xff08;detach&#xff09;当前的…

按从小到大顺序输出a, b, c(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;float a, b, c, t;//提示用户输入数据&#xff1b;printf("请输入数据a b c&#xff1a;");//获取用户输入数…

[大模型]Qwen-7B-Chat 接入langchain搭建知识库助手

Qwen-7B-Chat 接入langchain搭建知识库助手 环境准备 在autodl平台中租一个3090等24G显存的显卡机器&#xff0c;如下图所示镜像选择PyTorch–>2.0.0–>3.8(ubuntu20.04)–>11.8 接下来打开刚刚租用服务器的JupyterLab&#xff0c;并且打开其中的终端开始环境配置…

鸿蒙嵌入式开发工程师“钱”景如何?

鸿蒙嵌入式开发工程师前景如何&#xff1f;鸿蒙嵌入式开发工程师是指专门从事鸿蒙OS(HarmonyOS)在嵌入式设备上应用开发的工程师。随着鸿蒙OS的不断发展和应用场景的拓宽&#xff0c;鸿蒙嵌入式开发工程师的前景可以从以下几个方面进行展望&#xff1a; 1、鸿蒙嵌入式开发工程…

数据结构(循环单链表

目录 1. 讲解&#xff1a;2. C代码实现&#xff1a;小结&#xff1a; 1. 讲解&#xff1a; 循环链表又分为循环单链表、循环双链表。 2. C代码实现&#xff1a; #include <stdlib.h> #include <iostream> #include <stdio.h>using namespace std;#define E…

【leetcode面试经典150题】61. 反转链表 II(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

【C++】:C++关键字,命名空间,输入输出,缺省参数

目录 一&#xff0c;C关键字(C98)二&#xff0c;命名空间2.1 命名冲突2.2 关键字namespace2.2.1 命名空间中可以定义变量/函数/类型2.2.2 命名空间可以嵌套2.2.3 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。 2.3 命名空间的使用2.3.1 指定…

❤️‍FlyFlow工作流周更来咯~~

FlyFlow 借鉴了钉钉与飞书的界面设计理念&#xff0c;致力于打造一款用户友好、快速上手的工作流程工具。相较于传统的基于 BPMN.js 的工作流引擎&#xff0c;我们提供的解决方案显著简化了操作逻辑&#xff0c;使得用户能够在极短的时间内构建定制化的业务流程&#xff0c;即便…

Redis之路系列(3)纸上得来终觉浅(下)

03 纸上得来终觉浅(下) 基于Redis6&#xff0c;本章节主要介绍了Rdis的一些主要应用场景&#xff0c;包含了&#xff1a;大数据的过滤&#xff0c;分布式锁设计&#xff0c;并讲解了有趣的布隆过滤器原理&#xff0c;HyperLogLog 原理&#xff0c;二进制位数与存储大小计算的常…

汽车IVI中控开发入门及进阶(十五):AUTOSAR

前言: 随着汽车四化的进行,汽车电子系统standard标准化和coperation互操作性变得重要, AUTOSAR(AUTomotive Open System Architecture 汽车开放系统架构)框架已成为汽车行业的基础支柱。 AUTOSAR始自2000年,当时认识到标准化是有必要

Qt6连接MySQL

Qt6连接MySQL Qt6编译MySQL的过程太变态了&#xff0c;MinGW和MSVC都很费劲。 主要参考qt6.5.0MySQL驱动手动编译以及数据库连接详细教程以及注意事项附资源链接&#xff0c;这篇文章堪称保姆级教程&#xff0c;写的十分详细。 笔者这里踩了个坑&#xff0c;在按照上文中的过…

css设置文字撑满盒子

效果如上&#xff1a; <div style"width: 250px;background-color:red;text-align-last:justify;word-break: keep-all;">为中国崛起而读书</div>

【Linux】文件描述符——万字详解

目录​​​​​​​ 前言 预备知识 复习C语言的文件接口 写方式打开文件 追加方式打开文件 读方式打开文件 系统的文件接口 open close write read 文件描述符 0 & 1 & 2 理解文件描述符 文件描述符的分配规则 重定向的本质 dup2 理解Linux下一切…

Go 单元测试基本介绍

文章目录 引入一、单元测试基本介绍1.1 什么是单元测试&#xff1f;1.2 如何写好单元测试1.3 单元测试的优点1.4 单元测试的设计原则 二、Go语言测试2.1 Go单元测试概要2.2 Go单元测试基本规范2.3 一个简单例子2.3.1 使用Goland 生成测试文件2.3.2 运行单元测试2.3.3 完善测试用…

存储过程的使用(一)

目录 不带参数的存储过程 创建一个存储过程&#xff0c;向数据表 dept 中插入一条记录 带 IN 参数的存储过程 在存储过程中接受来自外部的数值&#xff0c;在存储过程中判断该数值是否大于零并显示 输入一个编号&#xff0c;查询数据表emp中是否有这个编号&#xff0c;如果…

博客系统项目测试(selenium+Junit5)

在做完博客系统项目之后&#xff0c;需要对项目的功能、接口进行测试&#xff0c;利用测试的工具&#xff1a;selenium以及Java的单元测试工具Junit进行测试&#xff0c;下面式测试的思维导图&#xff0c;列出该项目需要测试的所有测试用例&#xff1a; 测试结果&#xff08;全…

【Tesla T4为例】GPU安装最新版本NVIDIA Driver、CUDA、cuDNN、Anaconda、Pytorch

NVIDIA Driver 进入英伟达官网下载页面 按照以上方式选择即可得到>535.113.01版本的驱动&#xff0c;可以实现多卡推理&#xff0c;小于这个版本会导致多卡训练以及推理报错 虽然最新版本为550.54.15&#xff0c;但是535版本更加稳定&#xff0c;并且pytorch目前只支持到1…

云渲染采用了哪些核心技术来实现其高效的计算的?

云渲染运用云计算技术&#xff0c;将3D渲染任务分配至远程服务器集群以实现高速高效渲染&#xff0c;释放本地资源&#xff0c;缩短了影视动画、效果图等的制作周期&#xff0c;在影视、建筑、游戏等行业发挥关键作用。哪云渲染都用了哪些技术呢&#xff1f;我们一起来看看。 …
最新文章