select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。
一、I/O 多路复用技术概述
在传统网络编程的 “一连接一线程 / 进程” 模型中,每个网络连接都需独立的执行单元来处理。当连接数量维持在百级以内时,操作系统凭借成熟的资源调度机制,能够轻松管理这些线程或进程,实现高效的请求处理,系统响应延迟通常保持在毫秒级,吞吐量也较为稳定。
然而,随着连接规模向万级、百万级攀升,这种模型的弊端暴露无遗。以 Linux 系统为例,默认的线程数量上限(ulimit -u参数控制,一般为 1024 或 4096)成为第一道枷锁,即便通过参数调整,也难以突破硬件资源与操作系统架构的双重限制。更严峻的是,线程 / 进程的资源消耗呈线性增长:每个线程通常需分配 8MB - 16MB 的栈空间,百万级连接意味着至少消耗 8TB - 16TB 内存;同时,CPU 在处理上下文切换时,单次切换耗时约为 10 - 100 微秒,百万级线程频繁切换下,CPU 将有超过 80% 的时间被无用的上下文切换占据,导致实际业务处理性能骤降,系统响应延迟飙升至秒级,吞吐量近乎崩溃。
I/O 多路复用技术的出现彻底扭转了这一局面。它打破了 “连接数 - 线程数” 的线性关系,单个线程即可监控成千上万的文件描述符。通过高效的事件驱动机制,仅当文件描述符出现可读、可写或异常等就绪状态时,线程才会介入处理,大幅减少了资源浪费与上下文切换开销。实测数据显示,在同等硬件条件下,采用 I/O 多路复用技术的系统可将资源利用率提升 80% 以上,响应延迟降低至百微秒级,吞吐量提升数十倍,为高并发场景提供了稳定、高效的解决方案。
1.1 I/O 多路复用的优势
- 资源高效利用:减少线程或进程的数量,降低系统资源消耗。
- 高性能:避免大量上下文切换带来的性能损耗,提高 I/O 处理效率。
- 可扩展性:能够轻松应对大量连接,适应高并发场景。
二、select
2.1 原理
select 是最早的 I/O 多路复用技术,其核心思想是通过select系统调用,将需要监控的读、写和异常事件的文件描述符集合传递给内核。内核会轮询遍历这些文件描述符集合,检查是否有描述符就绪。如果有就绪的描述符,select调用返回,应用程序通过遍历之前传递的文件描述符集合,逐一检查每个描述符是否就绪,然后进行相应的 I/O 操作。
在 Linux 内核中,
fd_set
本质上是一个位图(bitmap),每个位对应一个文件描述符。例如,在 32 位系统中,一个fd_set
通常由 4 个 32 位整数组成,共 128 位,可表示 128 个文件描述符。在 64 位系统中,位图大小会相应扩展,但受限于系统参数FD_SETSIZE
(默认为 1024)。当用户调用
select
时,内核会将用户空间的fd_set
拷贝到内核空间,并创建对应的内核位图。这些位图分为三类:
- 读就绪位图:记录哪些描述符可读
- 写就绪位图:记录哪些描述符可写
- 异常就绪位图:记录哪些描述符发生异常
在 Linux 系统中,select系统调用的原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
其中,nfds是需要监控的文件描述符集合中最大描述符的值加 1;readfds、writefds和exceptfds分别是读、写和异常事件的文件描述符集合;timeout是超时时间,若设置为NULL,则select调用会一直阻塞,直到有描述符就绪。
系统调用过程
用户空间到内核空间的数据拷贝:
- 用户通过
readfds
、writefds
和exceptfds
传递需要监控的描述符集合- 内核使用
copy_from_user
将这些位图从用户空间拷贝到内核空间内核轮询检查:
- 内核遍历完整位图,而非仅用户注册的有效描述符
- 对于每个描述符,检查其对应的设备驱动程序或文件系统,判断是否处于就绪状态
- 若就绪,则在内核位图中标记该描述符
阻塞与唤醒机制(使用 ** 等待队列(wait queue)** 实现阻塞):
- 若没有描述符就绪且设置了超时时间,内核会将当前进程放入等待队列并进入睡眠状态
- 当某个描述符就绪或超时发生时,内核唤醒等待进程
结果返回:
- 内核将就绪描述符的位图拷贝回用户空间
select
返回就绪描述符的总数
2.2 优缺点
- 优点:跨平台性好,几乎在所有操作系统上都有实现。
- 缺点:
- 描述符数量限制:在 Linux 系统中,select默认最多只能监控 1024 个文件描述符(可通过修改系统参数调整,但会带来性能问题,例如位图过大导致每次系统调用的数据拷贝开销大,栈上分配过大临时位图导致栈溢出等)。
- 性能瓶颈:每次调用select都需要将文件描述符集合从用户空间拷贝到内核空间,无论描述符数量多少,每次
select
调用都需要将全部描述符集合从用户空间拷贝到内核空间,再将结果从内核空间拷贝回用户空间,随着描述符数量的增加,性能会急剧下降。
- 就绪描述符的低效处理:应用程序需要遍历整个文件描述符集合来找到就绪的描述符,这是一种线性查找方式,效率较低(时间复杂度为 O (n),当描述符数量庞大时,即使只有少数描述符就绪,内核仍需遍历全量集合,导致性能下降。)。
三、poll
3.1 原理
poll 是对 select 的改进,它采用了一种不同的数据结构来存储需要监控的文件描述符及其事件。poll使用一个pollfd结构体数组来表示要监控的文件描述符集合,每个pollfd结构体包含文件描述符、监控的事件类型(读、写、异常等)以及描述符的当前状态。
pollfd
结构体在内核中的定义如下:struct pollfd {int fd; // 文件描述符short events; // 请求监控的事件掩码short revents; // 实际发生的事件掩码 };
- events 字段:使用位掩码表示关注的事件类型,如
POLLIN
(可读)、POLLOUT
(可写)、POLLERR
(错误)等- revents 字段:由内核填充,指示该描述符实际发生的事件
- 内存对齐:结构体大小通常为 8 字节(32 位系统)或 16 字节(64 位系统),保证高效内存访问
poll系统调用的原型如下:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
其中,fds是指向pollfd结构体数组的指针,nfds是数组中元素的数量,timeout是超时时间(单位为毫秒)。
当调用poll时,内核会遍历pollfd数组,检查每个文件描述符的状态。如果有描述符就绪,poll调用返回,应用程序同样需要遍历pollfd数组来找到就绪的描述符并进行处理。
不同于之前select的fd_set这个固定大小位图结构,poll 在内核中维护一个事件表,本质是一个动态数组,用于存储用户注册的所有
pollfd
结构。当用户调用poll
时:
- 内核将用户空间的
pollfd
数组拷贝到内核事件表- 遍历事件表中的每个条目,调用对应文件描述符的
poll
方法(由驱动程序或文件系统实现)- 每个
poll
方法返回一个位掩码,表示该描述符当前就绪的事件类型- 内核将结果填充到
revents
字段,并更新事件表与 select 类似,poll 使用 ** 等待队列(wait queue)** 实现阻塞:
- 当没有描述符就绪时,内核将当前进程加入每个监控描述符的等待队列
- 当某个描述符状态变化时,对应的驱动程序会唤醒等待队列中的进程
- 进程被唤醒后,重新检查所有描述符状态
3.2 优缺点
- 优点:
- 无描述符数量限制:poll 使用动态分配的数组替代 select 的固定大小位图,,理论上没有像 select 那样的描述符数量限制,只受系统资源(如内存)的限制(实际应用中,用户空间可创建的文件描述符数量受
ulimit -n
限制(默认 1024),需通过setrlimit
系统调用调整)。 - 性能提升:相比 select,在数据结构上有所优化,减少了一些不必要的操作(poll 仅检查用户注册的描述符,而 select 需遍历完整位图,而非仅用户注册的有效描述符)。
- 缺点:
- 性能瓶颈依然存在:每次调用poll仍需将pollfd数组从用户空间拷贝到内核空间,并且内核和应用程序都需要线性遍历数组来检查和处理就绪描述符,随着描述符数量的增加,性能会下降。
3.3 与 select 的性能对比
操作 | select | poll |
---|---|---|
数据结构 | 固定大小位图(默认 1024 位) | 动态数组 |
描述符上限 | 受 FD_SETSIZE 限制(默认 1024) | 受内存限制 |
事件类型表示 | 三个独立位图(读 / 写 / 异常) | 位掩码(events/revents 字段) |
用户 - 内核拷贝开销 | 固定大小(与 FD_SETSIZE 相关) | 与描述符数量成正比 |
事件检查方式 | 全量位图遍历 | 数组元素遍历 |
就绪事件获取 | 需重新遍历所有描述符 | 直接读取 revents 字段 |
四、epoll(重点,现代网络库使用epoll+线程/进程池实现)
4.1 原理
epoll 是 Linux 内核为解决高并发 I/O 问题而引入的一种高效的 I/O 多路复用机制,它采用事件驱动的方式,避免了select和poll的线性查找问题。
epoll 在内核中主要通过三个关键数据结构实现:
epoll 实例(eventpoll 结构体):
- 每个 epoll 实例对应一个
eventpoll
结构体- 包含红黑树(用于存储注册的文件描述符)
- 就绪链表(用于存储就绪的文件描述符)
- 等待队列(用于实现阻塞机制)
红黑树(rbtree):
- 键值为文件描述符
- 每个节点包含
epitem
结构体,记录描述符、事件掩码和回调函数- 插入、删除、查找操作时间复杂度为 O (log n)
就绪链表(rdllist):
- 双向链表结构
- 当描述符就绪时,对应的
epitem
会被添加到该链表epoll_wait
直接从该链表获取就绪描述符
epoll 有两种工作模式:水平触发(Level Triggered,LT)和边缘触发(Edge Triggered,ET)。
1.水平触发(LT):只要文件描述符对应的读缓冲区或写缓冲区有数据可读或可写,就会一直触发相应的事件。应用程序可以多次读取或写入数据,直到缓冲区为空或填满。
- 回调函数检查描述符状态时,只要缓冲区有数据 / 空间,就会触发事件
- 即使应用程序未完全处理数据,下次调用
epoll_wait
仍会返回该描述符 - 实现简单,兼容性好,是默认模式
2.边缘触发(ET):只有当文件描述符的状态发生变化时(如从无数据可读变为有数据可读),才会触发一次事件。应用程序需要一次性尽可能多地读取或写入数据,否则可能会错过后续的事件。
- 仅在描述符状态发生变化时触发回调(如从无数据变为有数据)
- 要求应用程序必须一次性处理完所有数据(如使用循环读取直到返回 EAGAIN)
- 通过设置
EPOLLET
标志启用,性能更高但编程复杂度也更高
epoll 通过三个核心函数来实现:
- epoll_create:创建一个 epoll 实例,返回一个文件描述符,用于后续操作。
int epoll_create(int size);
- epoll_ctl:用于添加、修改或删除要监控的文件描述符及其事件。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
其中,epfd是epoll_create返回的文件描述符,op表示操作类型(如添加、修改、删除),fd是要监控的文件描述符,event是指向epoll_event结构体的指针,用于指定监控的事件类型。
当用户调用
epoll_ctl
注册事件时:
- 内核创建
epitem
结构体并插入红黑树- 为该描述符的设备驱动程序注册回调函数(
ep_poll_callback
)- 当描述符状态变化时,驱动程序调用回调函数
- 回调函数将
epitem
添加到就绪链表,并唤醒等待队列中的进程
- epoll_wait:等待就绪的文件描述符,当有描述符就绪时,返回就绪描述符的数量,并将就绪描述符的事件信息存储在用户提供的数组中。
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
其中,events是指向存储就绪事件的数组,maxevents是数组的大小,timeout是超时时间(单位为毫秒)。
4.2 优缺点
- 优点:
- 高性能:采用事件驱动机制,使用回调函数替代轮询,内核只将就绪的描述符返回给应用程序,避免了线性查找,大大提高了处理大量连接的效率。
- 低开销:只在添加、修改或删除文件描述符时需要进行系统调用,减少了用户空间和内核空间的数据拷贝次数。
- 无描述符数量限制:仅受系统资源限制。
- 缺点:仅在 Linux 系统上实现,不具备跨平台性;频繁的
epoll_ctl
调用会导致红黑树频繁插入 / 删除,影响性能
五、Reactor 模式
5.1 定义与核心思想
Reactor 模式是一种事件驱动的设计模式,用于处理多个客户端并发向服务器端发送请求的场景。它的核心思想是将 I/O 操作、事件分发和事件处理分离,通过一个或多个线程来监听和分发事件,将事件分发给对应的事件处理器进行处理。
5.2 组成部分
- Reactor:负责监听和分发事件,它使用 I/O 多路复用技术(如 select、poll、epoll)来监控多个文件描述符,当有事件发生时,根据事件类型将事件分发给相应的 Handler或Acceptor。
- Handler:事件处理器,负责处理具体的 I/O 事件,如读取数据、处理业务逻辑、发送响应等。每个 Handler 对应一个或多个文件描述符。
- Acceptor:用于接收新的连接请求,当有新的客户端连接时,Acceptor 创建一个新的 Handler 来处理该连接,并将其注册到 Reactor 中。
5.3 多 Reactor 多进程 / 线程
图片来源: 9.3 高性能网络模式:Reactor 和 Proactor | 小林coding
1. MainReactor:
- 核心职责:作为整个系统的入口,MainReactor 通过操作系统的 I/O 多路复用机制(如 Linux 的 epoll、Windows 的 IOCP),持续监听服务器套接字的连接事件(OP_ACCEPT)。当有新的客户端连接请求到达时,MainReactor 会讲事件分发给Acceptor处理。
2. Acceptor:
- 工作流程:当 MainReactor 监听到新连接事件后,会调用 Acceptor 进行处理。Acceptor 首先通过accept()方法接受客户端连接,创建对应的SocketChannel;随后,从SubReactorPool中选择一个空闲的 SubReactor,并将新连接的SocketChannel注册到该 SubReactor 的Selector上,同时为其绑定初始的读事件(OP_READ)和对应的EventHandler。
- 负载均衡策略:常见的 SubReactor 选择策略包括轮询法(Round-Robin)、最少连接数法(Least Connections)。
3. SubReactor:读写事件的执行者
- 功能定位:每个 SubReactor 运行在独立的线程中,负责监听分配给自己的多个SocketChannel的读写事件(OP_READ、OP_WRITE)。当事件就绪时,SubReactor 会将事件分发给对应的EventHandler进行处理,从而实现 I/O 操作与业务逻辑的分离。
- 事件循环机制:SubReactor 的事件循环与 MainReactor 类似,但处理的事件类型更丰富
4. EventHandler:业务逻辑的载体
- 处理流程:EventHandler负责具体的业务处理,遵循read -> 业务处理 -> send的流程。首先通过read方法从SocketChannel读取数据,将字节流解析为业务数据(如 HTTP 请求、RPC 协议包);然后调用业务逻辑进行处理,生成响应数据;最后通过send方法将响应数据写回客户端。
这种设计模式优点:
- 充分利用多核资源:MainReactor 专注连接管理,SubReactor 并行处理 I/O 读写,避免单线程瓶颈,实现 CPU 资源的高效利用。
- 高并发与低延迟:通过 I/O 多路复用和异步处理,系统可同时处理海量连接,减少请求响应延迟。
- 可扩展性强:新增 SubReactor 即可线性扩展系统性能,适应业务流量增长。
- 职责清晰:连接、I/O、业务逻辑分层处理,降低模块耦合度,提升代码可维护性。
5.4 应用场景
Reactor 模式广泛应用于高并发网络服务器中,如muduo、 Nginx、Netty 等。在这些应用中,Reactor 模式能够高效地处理大量客户端连接,提升系统的并发性能和响应速度。
六、总结
select、poll、epoll 作为 I/O 多路复用技术的不同实现,各有优缺点。select 和 poll 历史悠久,具有一定的跨平台性,但在高并发场景下存在性能瓶颈;epoll 是 Linux 系统下高效的 I/O 多路复用机制,采用事件驱动方式,能够很好地应对大量连接的高并发场景。而 Reactor 模式则是基于 I/O 多路复用技术构建的事件驱动设计模式,为高并发网络编程提供了清晰的架构和高效的事件处理方式。
相关文章:

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...