【Linux网络#18】:深入理解select多路转接:传统I/O复用的基石

📃个人主页:island1314
🔥个人专栏:Linux—登神长阶
目录
- 一、前言:🔥 I/O 多路转接
- 为什么需要I/O多路转接?
- 二、I/O 多路转接之 select
- 1. 初识 select
- 2. select 函数原型
- 2.1 关于 fd_set 结构
- 2.2 函数返回值
- 3. 理解 select 执行过程
- 3.1 socket 就绪条件
- 读就绪
- 写就绪
- 异常就绪(选学)
- 3.2 select 的特点
- 3.3 select 优缺点
- 3.4 注意事项
- 4. 代码示例
- 5. 使用场景
- 三、后言
一、前言:🔥 I/O 多路转接
💻 多路I/O转接服务器 \colorbox{cyan}{ 多路I/O转接服务器 } 多路I/O转接服务器 (或称为多任务I/O服务器)是一种高效管理多个I/O操作的技术,允许单线程或单进程同时监控和处理多个I/O事件(如网络套接字、文件描述符等)
- 核心思想:利用操作系统提供的多路I/O转接机制(如
select、poll、epoll等),由内核帮助应用程序高效地监视多个文件描述符(包括网络连接、管道、文件等)的状态变化,而不是让应用程序自己轮询每个连接的状态 - 核心目标:用最小资源开销实现高并发I/O处理,尤其适用于需要同时处理大量连接的场景(如Web服务器、实时通信系统等)
- 这种方式能够显著提高服务器的性能和可扩展性,尤其是在处理大量并发连接时
为什么需要I/O多路转接?
传统阻塞I/O模型中,每个I/O操作会阻塞线程直至完成。若需处理多个连接,通常需为每个连接分配独立线程/进程,导致资源消耗大、上下文切换频繁。
而I/O多路转接通过单线程监控多个I/O流,仅在I/O就绪时触发操作,避免了阻塞和资源浪费。
二、I/O 多路转接之 select
1. 初识 select
💻 系统提供 select \colorbox{pink}{ select } select 函数来实现多路复用 输入 / 输出 模型.
select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;- 程序会停在
select这里等待, 直到被监视的文件描述符有一个或多个发生了状态改变;
核心原理
select是一种 同步I/O多路复用 机制,允许程序在一个线程中监听多个文件描述符(如套接字、文件等)的可读、可写或异常事件。- 其核心是通过 **轮询(polling)**检查文件描述符状态,并阻塞等待直到至少一个描述符就绪或超时。
2. select 函数原型
💤 select 的函数原型如下:
#include <sys/select.h>int select(int nfds, // 监控的最大文件描述符值 +1fd_set *readfds, // 监听可读事件的描述符集合fd_set *writefds, // 监听可写事件的描述符集合fd_set *exceptfds, // 监听异常事件的描述符集合struct timeval *timeout // 超时时间(NULL为无限等待)
);// 操作fd_set的宏:
FD_ZERO(fd_set *set); // 清空集合
FD_SET(int fd, fd_set *set); // 添加描述符到集合
FD_ISSET(int fd, fd_set *set); // 检查描述符是否在集合中
FD_CLR(int fd, fd_set *set); // 从集合移除描述符
📚 参数解释:
nfds是需要监视的最大的文件描述符值 +1rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合 , 可写文件描述符的集合 及 异常文件描述符的集合timeout为 结构体timeval, 用来设置select()的等待时间/* A time value that is accurate to the nearestmicrosecond but also has a range of years. */ struct timeval {__time_t tv_sec; /* Seconds. */__suseconds_t tv_usec; /* Microseconds. */ };
📚 参数 timeout 取值:
-
NULL: 则表示select()没有timeout,select将一直被阻塞, 直到某个文件描述符上发生了事件 -
0: 仅检测描述符集合的状态, 然后立即返回, 并不等待外部事件的发生(非阻塞) -
特定的时间值:
struct timeval timeout = {10, 0}: 如果在指定的时间段里没有事件发生,select将超时返回
2.1 关于 fd_set 结构
typedef long int __fd_mask;/* It's easier to assume 8-bit bytes than to get CHAR_BIT. */
#define __NFDBITS (8 * (int) sizeof (__fd_mask))
#define __FDELT(d) ((d) / __NFDBITS)
#define __FDMASK(d) ((__fd_mask) 1 << ((d) % __NFDBITS))/* fd_set for select and pselect. */
typedef struct{/* XPG4.2 requires this member name. Otherwise avoid the namefrom the global namespace. */
#ifdef __USE_XOPEN__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->__fds_bits)
#endif} fd_set;/* Maximum number of file descriptors in `fd_set'. */
#define FD_SETSIZE __FD_SETSIZE //__FD_SETSIZE等于1024/* Access macros for `fd_set'. */
#define FD_SET(fd, fdsetp) __FD_SET (fd, fdsetp)
#define FD_CLR(fd, fdsetp) __FD_CLR (fd, fdsetp)
#define FD_ISSET(fd, fdsetp) __FD_ISSET (fd, fdsetp)
#define FD_ZERO(fdsetp) __FD_ZERO (fdsetp)
- 其实这个结构就是一个 整数数组,更严格的说, 是一个 “位图” . 使用位图中对应的位来表示要监视的文件描述符.
- 一个long int类型的数组。因为每一位可以代表一个文件描述符。所以fd_set最多表示1024个文件描述符!
- 提供了一组操作
fd_set的接口, 来比较方便的操作位图
void FD_CLR(int fd, fd_set *set); // 用来清除描述词组 set 中相关 fd 的位
int FD_ISSET(int fd, fd_set *set); // 用来测试描述词组 set 中相关 fd 的位是否为真
void FD_SET(int fd, fd_set *set); // 用来设置描述词组 set 中相关 fd 的位
void FD_ZERO(fd_set *set); // 用来清除描述词组 set 的全部位
2.2 函数返回值
- 执行成功则返回 文件描述符状态已改变的个数
- 如果返回 0 代表在描述符状态改变前已超过 timeout 时间
- 当有错误发生时则返回-1, 错误原因存于 errno, 此时参数 readfds, writefds, exceptfds 和 timeout 的值变成不可预测
🙅 错误值可能为:
EBADF: 文件描述词为无效的或该文件已关闭EINTR:此调用被信号所中断EINVAL: 参数 n 为负值ENOMEM: 核心内存不足
3. 理解 select 执行过程
🦈 理解 select 模型的关键在于理解 fd_set, 为说明方便, 取 fd_set 长度为 1 字节, fd_set 中的每一 bit 可以对应一个文件描述符 fd_set。 则 1 字节长的 fd_set 最大可以对应 8 个 fd.
- 执行
fd_set;FD_ZERO(&set);则set用位表示是 0000,0000 - 若 fd= 5,执行
FD_SET(fd,&set); 后set变为 0001,0000(第 5 位置为 1) - 若再加入 fd= 2, fd=1,则
set变为 0001,0011 - 执行
select(6,&set,0,0,0)阻塞等待 select返回, 此时set变为 0000,0011。 注意: 没有事件发生的 fd=5 被清空
3.1 socket 就绪条件
读就绪
socket内核中, 接收缓冲区中的字节数, 大于等于低水位标记SO_RCVLOWAT. 此时可以无阻塞的读该文件描述符, 并且返回值大于 0;socketTCP 通信中, 对端关闭连接, 此时对该socket读, 则返回 0;- 监听的
socket上有新的连接请求; socket上有未处理的错误;
写就绪
socket内核中, 发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小), 大于等于低水位标记SO_SNDLOWAT, 此时可以无阻塞的写, 并且返回值大于 0;socket的写操作被关闭(close 或者 shutdown). 对一个写操作被关闭的socket进行写操作, 会触发 SIGPIPE 信号;socket使用非阻塞 connect 连接成功或失败之后;socket上有未读取的错误;
异常就绪(选学)
- socket 上收到带外数据. 关于带外数据, 和 TCP 紧急模式相关(回忆 TCP 协议头中, 有一个紧急指针的字段), 自己收集相关资料
3.2 select 的特点
- 可监控的文件描述符个数取决于
sizeof(fd_set)的值. 我这边服务器上 sizeof(fd_set)= 512, 每 bit 表示一个文件描述符, 则我服务器上支持的最大文件描述符是 512*8=4096. - I将 fd 加入
select监控集的同时, 还要再使用一个数据结构array保存放到select监控集中的 fd,- 用于再
select返回后,array作为源数据和fd_set进行FD_ISSET判断** select返回后会把以前加入的但并无事件发生的 fd 清空, 则每次开始select前都要重新从array取得 fd 逐一加入(FD_ZERO 最先), 扫描array的同时 取得 fd 最大值maxfd, 用于select的第一个参数
- 用于再
备注: fd_set 的大小可以调整, 可能涉及到重新编译内核.
3.3 select 优缺点
| 优点 | 缺点 |
|---|---|
| 跨平台支持(所有UNIX/Linux系统) | 文件描述符数量受限(默认1024,由FD_SETSIZE定义) |
| 简单易用,适合少量并发场景 | 线性扫描,时间复杂度O(n)(效率随描述符数量下降) |
| 超时机制灵活 | 每次调用需重置fd_set(额外内存拷贝开销) |
- 每次调用 select:都需要手动设置 fd 集合(从用户态拷贝到内核态), 从接口使用角度来说也非常不便,而且 这个开销在 fd 很多时会很大
- 同时每次调用 select 都需要在内核遍历传递进来的所有 fd, 这个开销在 fd 很多时也很大
3.4 注意事项
- 描述符上限:通过
FD_SETSIZE宏定义(通常1024),需重新编译内核修改。 - 性能问题:当监控数千描述符时,
select的轮询效率远低于epoll或kqueue。 - 水平触发:
select是水平触发模式,若未处理就绪事件,会持续通知。 - 非阻塞I/O:结合非阻塞socket可避免单次
read/write阻塞整个程序。
4. 代码示例
示例一:检测标准输入输出
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>int main()
{fd_set read_fds;FD_ZERO(&read_fds); // 清空FD_SET(0, &read_fds);while(true){printf("> ");fflush(stdout);int ret = select(1, &read_fds, NULL, NULL, NULL);if(ret < 0){perror("Select");continue;}if(FD_ISSET(0, &read_fds)){char buf[1024] = {0};read(0, buf, sizeof(buf) - 1);printf("Input: %s", buf);}else{printf("Error! Invalid fd\n");continue;}FD_ZERO(&read_fds);FD_SET(0, &read_fds);}return 0;
}
- 当只检测文件描述符 0(标准输入)时,因为输入条件只有在你有输入信息的时候才成立,所以如果一直不输入,就会产生超时信息
示例二:TCP 服务器使用 select 处理多客户端
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/select.h>
#include <cstring>#define MAX_CLIENTS 10
#define BUFFER_SIZE 1024int main() {int server_fd, new_socket;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[BUFFER_SIZE] = {0};// 创建TCP socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 设置socket选项(允许地址重用)if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(8080);// 绑定socket到端口if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 开始监听if (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}fd_set readfds; // 描述符集合int client_sockets[MAX_CLIENTS] = {0}; // 客户端socket数组int max_sd;while (true) {FD_ZERO(&readfds); // 清空集合FD_SET(server_fd, &readfds); // 添加服务器socket到监听集合max_sd = server_fd;// 添加所有客户端socket到集合for (int i = 0; i < MAX_CLIENTS; i++) {int sd = client_sockets[i];if (sd > 0) {FD_SET(sd, &readfds);if (sd > max_sd) max_sd = sd;}}// 调用select,阻塞等待事件int activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);if ((activity < 0) && (errno != EINTR)) {perror("select error");}// 检查服务器socket是否有新连接if (FD_ISSET(server_fd, &readfds)) {if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}// 将新客户端socket加入数组for (int i = 0; i < MAX_CLIENTS; i++) {if (client_sockets[i] == 0) {client_sockets[i] = new_socket;std::cout << "New client connected, socket fd: " << new_socket << std::endl;break;}}}// 处理客户端数据for (int i = 0; i < MAX_CLIENTS; i++) {int sd = client_sockets[i];if (FD_ISSET(sd, &readfds)) {int valread = read(sd, buffer, BUFFER_SIZE);if (valread == 0) { // 客户端断开连接getpeername(sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);std::cout << "Client disconnected" << std::endl;close(sd);client_sockets[i] = 0; // 清除socket} else { // 处理数据buffer[valread] = '\0';std::cout << "Received: " << buffer << std::endl;send(sd, buffer, strlen(buffer), 0); // 回显数据}}}}return 0;
}
- 初始化服务器
- 创建TCP socket,绑定端口并开始监听。
- 设置
SO_REUSEADDR允许地址重用(避免端口占用)。
select监听流程- 使用
fd_set管理需要监听的描述符集合。 - 每次循环重新初始化集合,添加服务器socket和所有客户端socket。
- 调用
select阻塞等待事件,返回就绪的描述符数量。
- 使用
- 处理新连接
- 当服务器socket就绪(
FD_ISSET),调用accept接受新连接。 - 将新客户端socket存入数组。
- 当服务器socket就绪(
- 处理客户端数据
- 遍历所有客户端socket,检查是否有数据可读。
- 若
read返回0,表示客户端断开连接,关闭socket并清理数组。 - 否则回显接收到的数据。
5. 使用场景
- 需要兼容多平台的轻量级应用。
- 并发连接数较少(如<1000)。
- 超时机制需要精细控制的场景(如同时等待I/O和定时任务)
三、后言
【★,°:.☆( ̄▽ ̄)/$:.°★ 】那么本篇到此就结束啦,如果有不懂 和 发现问题的小伙伴可以在评论区说出来哦,同时我还会继续更新关于【Linux】的内容,比如:多路转接之
epoll、poll模型,请持续关注我 !!

相关文章:
【Linux网络#18】:深入理解select多路转接:传统I/O复用的基石
📃个人主页:island1314 🔥个人专栏:Linux—登神长阶 目录 一、前言:🔥 I/O 多路转接 为什么需要I/O多路转接? 二、I/O 多路转接之 select 1. 初识 select2. select 函数原型2.1 关于 fd_set 结…...
华院计算3项应用成果入选钢铁行业智能制造解决方案推荐目录(2024年)
近日,中国钢铁工业协会发布《钢铁行业智能制造解决方案推荐目录(2024年)》。由中国钢铁工业协会、钢铁行业智能制造联盟共同开展了2024年钢铁行业智能制造解决方案及数字化转型典型场景应用案例遴选、智能制造创新大赛(钢铁行业赛…...
python使用cookie、session、selenium实现网站登录(爬取信息)
一、使用cookie 这段代码演示了如何使用Python的urllib和http.cookiejar模块来实现网站的模拟登录,并在登录后访问需要认证的页面。 # 导入必要的库 import requests from urllib import request, parse# 1. 导入http.cookiejar模块中的CookieJar类,用…...
vector模拟实现2
文章目录 vector的模拟实现erase函数resize拷贝构造赋值重载函数模版构造及其细节结语 我们今天又见面啦,给生活加点impetus!!开启今天的编程之路 今天我们来完善vector剩余的内容,以及再探迭代器失效! 作者ÿ…...
观察者模式在Java单体服务中的运用
观察者模式主要用于当一个对象发生改变时,其关联的所有对象都会收到通知,属于事件驱动类型的设计模式,可以对事件进行监听和响应。下面简单介绍下它的使用: 1 定义事件 import org.springframework.context.ApplicationEvent;pu…...
详解相机的内参和外参,以及内外参的标定方法
1 四个坐标系 要想深入搞清楚相机的内参和外参含义, 首先得清楚以下4个坐标系的定义: 世界坐标系: 名字看着很唬人, 其实没什么大不了的, 这个就是你自己定义的某一个坐标系。 比如, 你把房间的某一个点定…...
在线sql 转 rust 模型(Diesel、SeaORM),支持多数据 mysql, pg等
SQL 转 Rust 在 Rust 语言中,常用 Diesel 和 SeaORM 进行数据库操作。手写 ORM 模型繁琐,gotool.top 提供 SQL 转 Diesel、SeaORM 工具,自动生成 Rust 代码,提高开发效率。 特色 支持 Diesel / SeaORM,生成符合规范…...
高并发内存池(二):Central Cache的实现
前言:本文将要讲解的高并发内存池,它的原型是Google的⼀个开源项⽬tcmalloc,全称Thread-Caching Malloc,近一个月我将以学习为目的来模拟实现一个精简版的高并发内存池,并对核心技术分块进行精细剖析,分享在…...
[Windows] VutronMusic v1.6.0 音乐播放器纯净版,可登录同步
VutronMusic-简易好看的PC音乐播放器 链接:https://pan.xunlei.com/s/VOMq7P_fTyhLUXeGerDVhrCTA1?pwduvut# VutronMusic v1.6.0 音乐播放器纯净版,可登录同步...
macvlan 和 ipvlan 实现原理及设计案例详解
一、macvlan 实现原理 1. 核心概念 macvlan 允许在单个物理网络接口上创建多个虚拟网络接口,每个虚拟接口拥有 独立的 MAC 地址 和 IP 地址。工作模式: bridge 模式(默认):虚拟接口之间可直接通信,类似交…...
【蓝桥杯】每日练习 Day19,20
目录 前言 蒙德里安的梦想 分析 最短Hamilton路径 分析 代码 乌龟棋 分析 代码 松散子序列 分析 代码 代码 前言 今天不讲数论(因为上课学数论真是太难了,只学了高斯消元)所以今天就不单独拿出来讲高斯消元了。今天讲一下昨天和…...
《AI大模型应知应会100篇》第7篇:Prompt Engineering基础:如何与大模型有效沟通
第7篇:Prompt Engineering基础:如何与大模型有效沟通 摘要 Prompt Engineering(提示工程)是与大模型高效沟通的关键技能。通过精心设计的Prompt,可以让模型生成更准确、更有用的结果。本文将从基础知识到高级策略&…...
微服务架构技术栈选型避坑指南:10大核心要素深度拆解
微服务架构的技术栈选型直接影响系统的稳定性、扩展性和可维护性。以下从10大核心要素出发,结合主流技术方案对比、兼容性评估、失败案例及优化策略,提供系统性选型指南。 1. 服务框架与通信 关键考量点 扩展性:框架需支持定制化扩展&#x…...
Elasticsearch 正排索引
一、正排索引基础概念 在 Elasticsearch 中,正排索引用于存储完整的文档内容,以便通过文档ID 快速定位文档的字段值。正排索引通过 Doc Values 和 Store Fields 两种形式,为聚合、排序、脚本计算等场景提供高效支持。Doc Values 的列式存储设…...
Spring实现WebScoket
SpringWeb编程方式分为Servlet模式和响应式。Servlet模式参考官方文档:Web on Servlet Stack :: Spring Framework,响应式(Reacive)参考官方文档:Web on Reactive Stack :: Spring Framework。 WebSocket也有两种编程方…...
Token是什么?
李升伟 整理 “Token” 是一个多义词,具体含义取决于上下文。以下是几种常见的解释: 1. 计算机科学中的 Token 定义:在编程和计算机科学中,Token 是源代码经过词法分析后生成的最小单位,通常用于编译器和解释器。 …...
odoo-045 ModuleNotFoundError: No module named ‘_sqlite3‘
文章目录 一、问题二、解决思路 一、问题 就是项目启动,本来好好地,忽然有一天报错,不知道什么原因。 背景: 我是在虚拟环境中使用的python3.7。 二、解决思路 虚拟环境和公共环境直接安装 sqlite3 都会报找不到这个库的问题…...
cesium加载CTB生成的地形数据
由于CTB生成的地形数据是压缩的(gzip)格式,需要在nginx加上特殊配置才可以正常加载,NGINX全部配置如下 worker_processes 1; events {worker_connections 1024; } http {include mime.types;default_type application/o…...
前端JS高阶技法:序列化、反序列化与多态融合实战
✨ 摘要 序列化与反序列化作为数据转换的核心能力,与多态这一灵活代码设计的核心理念,在现代前端开发中协同运作,提供了高效的数据通信与扩展性支持。 本文从理论到实践,系统解析: 序列化与反序列化的实现方式、使用…...
TS中的Class
基本用法 implements implements 关键字用于传递对类产生约束的数据类型 interface AnimalInfo{name:stringrace:stringage:number }interface AnimalCls{info:AnimalInfosayName():void} class Animal implements AnimalCls{info:AnimalInfoconstructor(info:AnimalInfo) {t…...
RustDesk 开源远程桌面软件 (支持多端) + 中继服务器伺服器搭建 ( docker版本 ) 安装教程
在需要控制和被控制的电脑上安装软件 github开源仓库地址 https://github.com/rustdesk/rustdesk/releases 蓝奏云盘备份 ( exe ) https://geek7.lanzouw.com/iPf592sadqrc 密码:4esi 中继服务器设置 使用docker安装 sudo docker image pull rustdesk/rustdesk-server sudo…...
【计网速通】计算机网络核心知识点与高频考点——数据链路层(二)
数据链路层核心知识点(二) 涵盖局域网、广域网、介质访问控制(MAC层)及数据链路层设备 上文链接:https://blog.csdn.net/weixin_73492487/article/details/146571476 一、局域网(LAN,Loacl Area Network&am…...
STM32单片机入门学习——第3-4节: [2-1、2]软件安装和新建工程
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.01 STM32开发板学习——第一节: [1-1]课程简介 前言开发板说明引用解答和…...
W3C XML Schema 活动
W3C XML Schema 活动 概述 W3C XML Schema(XML Schema)是万维网联盟(W3C)定义的一种数据描述语言,用于定义XML文档的结构和约束。XML Schema为XML文档提供了一种结构化的方式,确保数据的一致性和有效性。本文将详细介绍W3C XML Schema的活动,包括其发展历程、主要特点…...
爬虫【Scrapy-redis分布式爬虫】
Scrapy-redis分布式爬虫 1.Scrapy-redis实现增量爬虫 增量爬虫的含义 就是前面所说的的暂停、恢复爬取 安装 # 使用scrapy-redis之前最好将scrapy版本保持在2.8.0版本, 因为2.11.0版本有兼容性问题 pip install scrapy==2.8.0 pip install scrapy-redis -i https://pypi.tun…...
intellij Idea 和 dataGrip下载和安装教程
亲测有效 第一步:卸载老版本idea/Datagrip (没有安装过的可跳过此步骤) 第二步:下载idea/dataGrip安装包 建议选择2022以后的版本 官网: https://www.jetbrains.com/datagrip/download/other.html 选择dataGrip 的…...
轻量级搜索接口技术解析:快速实现关键词检索的Java/Python实践
Hi,你好! 轻量级搜索接口技术解析:快速实现关键词检索的Java/Python实践 接口特性与适用场景 本接口适用于需要快速集成搜索能力的开发场景,支持通过关键词获取结构化搜索结果。典型应用场景包括: 垂直领域信息检索…...
架构设计基础系列:事件溯源模式浅析
图片来源网络,侵权删 1. 引言 1.1 研究背景 传统CRUD模型的局限性:状态覆盖导致审计困难、无法追溯历史。分布式系统复杂性的提升:微服务架构下数据一致性、回滚与调试的需求激增。监管合规性要求:金融、医疗等领域对数…...
ResNet系列和ViT系列预训练模型权重文件下载
一、简单介绍 OpenAI CLIP项目提供的预训练模型权重文件列表,主要包含两种架构系列和不同规模配置: ResNet系列 (RN) 基础版本:RN50(ResNet-50)扩展版本:RN50x4、RN50x16、RN50x64(宽度扩展&am…...
【力扣hot100题】(035)二叉树的中序遍历
正常方法递归很简单,于是又学了一种栈的方法。 原理如下:每次循环先尽量将目前节点入栈并左移,没有左节点时回到栈首节点将目前节点放入结果容器中并移出栈外,目前节点变为该节点的右节点,循环结束条件是目前节点为nu…...
