《Linux 网络编程》深入理解 IO 多路复用:select 函数详解与 Echo 服务实战
小叶-duck个人主页❄️个人专栏《Data-Structure-Learning》《C入门到进阶自我学习过程记录》《Linux系统从入门到实践》《Linux网络从入门到实践》《Qt 方寸极境》 《MySQL》✨未择之路不须回头已择之路纵是荆棘遍野亦作花海遨游目录前言一、多路转接的本质“等” 和 “拷贝” 分离1.1 IO 模型原理拆分1.2 什么是 “条件就绪”1.4 常见多路复用方案对比二、select 函数详解2.1 函数原型2.2 参数详细解析2.2.1 nfds 参数2.2.2 fd_set 与三类事件集合2.2.3 fd_set 配套操作宏2.2.4 timeout 超时参数2.3 返回值规则2.4 select 三种等待模式2.4.1 永久阻塞模式2.4.2 限时阻塞模式2.4.3 非阻塞轮询模式三、select 实战从零实现 Echo 服务端开发5.1 基础组件回顾5.2 select 服务端核心类实现5.3 主函数入口5.4 编译与运行结束语前言在上一篇《Linux 网络编程》深入理解五种 IO 模型从 IO 本质到非阻塞 IO 实战中我们学习了 IO 的本质逐一拆解了阻塞、非阻塞、信号驱动、IO 多路复用、异步 IO 五大模型也通过 fcntl 完成了非阻塞 IO 的代码实践分清了同步与异步 IO 的核心区别。有了五种 IO 模型的理论基础接下来我们就可以正式进入 IO 多路复用的详细学习。本篇将从多路转接的核心思想出发讲解 select 函数的完整用法包含函数原型、参数解析、等待模式、返回值规则最后落地到代码实战从零编写基于 select 的 Echo 服务端。IO 多路复用是 Linux 高并发网络编程的核心基石而 select 是我们接触的第一个多路复用接口。吃透 select 的原理、优缺点也能为后续学习 poll、epoll 打下扎实的底层认知。一、多路转接的本质“等” 和 “拷贝” 分离回顾前面学习的结论任何 IO 操作都可以拆分为两大核心阶段等待数据就绪、内核与用户空间之间的数据拷贝。传统read、recv这类系统调用会将等待与拷贝两个步骤封装在一起。线程如果不先对等待进行处理调用后就会先阻塞等待 fd 条件就绪就绪之后再执行数据拷贝。多路转接多路复用的核心思想就是将这两个步骤解耦拆分。1.1 IO 模型原理拆分等交给select、poll、epoll这类专用函数。单个调用可以同时监听、等待多个文件描述符fd只负责检测 fd 是否满足就绪条件。拷贝仍然使用read、recv、write、send完成。只有当多路复用函数通知我们某个 fd 就绪之后才去调用读写接口执行数据拷贝。这样当我们再调用读写函数的时候就不会再先后进行等和拷贝两个过程了而会直接进行拷贝。多路转接本质上是就绪事件通知机制。它只负责监测哪些 fd 已经满足读写条件当事件就绪通知上层程序由程序主动发起后续真正的数据拷贝操作。可以用之前的钓鱼例子理解一个钓鱼人同时持有多根鱼竿每根鱼竿对应一个文件描述符。传统 IO 是只盯着一根鱼竿等待多路转接可以一次性看管全部鱼竿只要任意一根鱼竿有鱼上钩事件就绪就通知程序去处理。1.2 什么是 “条件就绪”select 等多路复用函数核心工作就是等待 fd 的条件就绪。就绪事件分为读就绪、写就绪两大类读就绪内核接收缓冲区存在可读取的数据或是套接字收到新连接请求。写就绪内核发送缓冲区存在空闲空间可以向内核写入数据。当某个 fd 满足上面任意一类条件select就会返回通知应用程序该 fd 已经就绪可以执行对应的 IO 操作。补充知识点新创建的 fd默认发送缓冲区和接收缓冲区都为空也就是说一开始默认没有内容可以读取写的缓冲区全空可以写入数据。因此读事件默认不就绪写事件默认就是就绪状态。1.4 常见多路复用方案对比Linux 提供三种主流多路复用实现核心思想一致但底层数据结构、性能、使用限制差异很大。方案支持系统底层数据结构连接数上限效率selectPOSIX 兼容Linux/Windows/macOS位图固定上限默认 1024较低内核需要线性遍历全部 fdpollLinux/macOS链表无固定上限受内存限制中等依旧需要线性遍历 fd 集合epoll仅 Linux红黑树 就绪链表无固定上限高仅返回活跃就绪 fd无需遍历全部 fd虽然 epoll 是三者中性能最优的方案但select是基础、跨平台的实现是我们学习多路转接的入门重点。二、select 函数详解select是 Linux 最早实现的多路转接接口属于事件驱动型系统调用。它的核心能力就是在一次调用中同时等待多个文件描述符区分读、写、异常三类就绪事件。下面从函数原型、参数、配套宏、返回值、三种等待模式完整拆解。2.1 函数原型使用select需要引入头文件sys/select.h函数原型#include sys/select.h int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);这个函数看起来参数很多但其实逻辑非常清晰。下面我们逐个拆解每一个参数的含义。2.2 参数详细解析2.2.1 nfds 参数nfds不是监听 fd 的总数量。取值规则所有被监听 fd 里面的最大值 1。内核依靠这个值确定遍历范围只需要扫描 0 到 nfds-1 的 fd减少遍历开销。示例监听 fd3、fd5、fd7最大 fd 是 7nfds设置为718。2.2.2 fd_set 与三类事件集合readfds、writefds、exceptfds类型都是fd_set分别代表读事件集合、写事件集合、异常事件集合。fd_set底层是位图结构每一个比特位对应一个 fd 编号比特位为 1 代表监听该 fd 对应的事件。_FD_SETSIZE默认值为1024但不同的机器可能这个值不相同这也就是说 select 最多只能同时监听_FD_SETSIZE这么多 fd 的个数这也是后面我们讲解select的缺点的其中之一。重点这三个 fd_set 属于输入输出型参数输入阶段用户通过位图告诉内核需要监听哪些 fd 的哪些事件。输出阶段select 返回时内核会修改位图仅保留就绪 fd 对应的比特位未就绪 fd 的 bit 会被清空。 因此每次调用 select 之前必须重新初始化、填充 fd_set 集合。如果同一个 fd 需要同时监听读、写事件可以把 fd 同时加入读集合与写集合。内核只会反馈我们主动添加到集合里的 fd 事件。2.2.3 fd_set 配套操作宏fd_set底层虽然是由结构体封装数组实现的位图但我们不能直接手动位运算来修改比特位。不同操作系统、硬件平台下底层数组的存储排布、字长存在差异手写位运算代码会丧失跨平台兼容性。操作系统已经封装好 4 个标准宏直接调用宏接口就能安全、可移植地完成位图操作。// 清空fd_set中所有比特位每次循环监听前一般要执行 void FD_ZERO(fd_set *set); // 将指定fd加入集合标记为需要监听 void FD_SET(int fd, fd_set *set); // 将指定fd从集合移除取消监听 void FD_CLR(int fd, fd_set *set); // 检测fd对应的bit是否置1用来判断fd是否就绪 int FD_ISSET(int fd, fd_set *set);FD_ZERO清空整个文件描述符集合将所有比特位置 0。FD_SET把指定 fd 对应的比特位设置为 1代表将该 fd 加入监听集合。FD_CLR把指定 fd 对应的比特位设置为 0代表将该 fd 从监听集合移除。FD_ISSET检测 fd 对应的比特位判断该 fd 是否处于就绪状态。2.2.4 timeout 超时参数timeout是struct timeval 结构体指针用来设置 select 的等待时长同样属于输入输出型参数。struct timeval { time_t tv_sec; // 秒 suseconds_t tv_usec;// 微秒 };timeout 存在三种配置方式对应三种等待模式NULL永久阻塞模式select 持续阻塞直到任意 fd 事件就绪才返回没有超时。{0,0}非阻塞轮询模式不阻塞立刻检测 fd 状态检测完直接返回CPU 占用高不适合长时间使用。设置固定时间限时阻塞模式阻塞等待指定时长。如果期间事件就绪函数返回同时timeout会被内核修改保存剩余等待时间超时无事件则返回 0。2.3 返回值规则select返回值分为三种场景返回 0成功返回就绪文件描述符的总个数。返回 0等待超时在 timeout 指定时间内没有任何 fd 触发就绪事件。返回 0调用出错错误码保存在errno。补充当 timeout 设置为 NULL 永久阻塞时select 永远不会返回 0返回 0 只会出现在设置了超时时间的场景。2.4 select 三种等待模式2.4.1 永久阻塞模式timeout 传入 NULL。线程阻塞在 select 调用直到被监听 fd 有事件就绪才返回没有超时退出。适合持续后台监听的服务场景。2.4.2 限时阻塞模式给timeval设置固定时长例如struct timeval timeout{5,0}代表最多阻塞等待 5 秒。在等待时间内一旦事件就绪select 立刻返回同时更新 timeout 为剩余等待时长超过时间没有事件就绪则返回 0。该模式兼顾事件监听与定时任务是工程最常用的模式。2.4.3 非阻塞轮询模式timeval设置{ 0, 0 }。调用 select 不会阻塞线程马上扫描全部 fd 集合有就绪事件返回就绪数量无就绪直接返回 0。会持续循环扫描 fdCPU 消耗大一般不推荐长期使用。三、select 实战从零实现 Echo 服务端开发在上面我们学习了 select IO 多路复用的理论原理现在我们可以实现一个基于select的 TCP 服务器。本篇文章先完成框架搭建实现监听套接字、接收新连接后续再扩展客户端读写回声逻辑。5.1 基础组件回顾本次的实战依然会复用之前封装好的通用基础组件组件的完整实现可以参考之前的博客文章。InetAddr.hpp封装网络地址转换提供 IP、端口的转换与字符串打印功能Socket.hppTCP 套接字封装包含 socket 创建、bind 绑定、listen 监听、accept 获取连接等接口Logger.hpp线程安全日志模块方便打印调试、错误、提示信息Mutex.hpp互斥锁与 RAII 锁守卫用于多线程场景的资源保护5.2 select 服务端核心类实现我们封装SelectServer类作为服务主体核心逻辑全部写在这个类中。#pragma once #include iostream #include memory #include Socket.hpp using namespace SocketModule; class SelectServer { const static int nums sizeof(fd_set) * 8; const static int defaultfd -1; // 表示当前位置没有连接fd占用 public: SelectServer(int port) : _listensock(std::make_uniqueTcpSocket()), _isrunning(false) // 派生类对象传给基类指针 { _listensock-BuildTcpSocketMethod(port); // 初始化辅助数组fd_array(所有位置初始化为-1表示所有位置没有连接fd占用) // 后续借助这个defaultfd我们就可以重复利用这些位置对连接fd进行存放 for (int i 0; i nums; i) { fd_array[i] defaultfd; } fd_array[0] _listensock-Fd(); } ~SelectServer() { } void Start() { _isrunning true; while (_isrunning) { // // InetAddr peer; // // auto res _listensock-Accept(peer); // 我们在select多路转接这里,我们可以直接进行accept吗?不行 // // 因为1istensockfd也是一个fd进程怎么知道1istenfd上面有新连接到来了呢 // // accept本质就是一个阻塞IOaccept真正关心的只是传入的指定文件描述符listensockfd的读事件 // // 将listensockfd添加到select函数中让select只帮我关心listensockfd读事件是否就绪 // // 并且将时间设置成阻塞(nullptr结论listensockfd的读事件就绪 新连接到来 // // 虽然我们知道fd_set所对应的数据类型就是由结构体封装的数组所表示的位图 // // 但是我们并不能直接进行位操作把特定的比特位设置到这个位图中 // // 因为我们所实现的位操作设置不一定具备跨平台性为了保证任何系统都能完成设置操作 // // 操作系统为我们提供了诸多宏操作不需要我们自己进行位操作调用对应的宏就可以完成比特位设置了 // fd_set rfds; // 定义rfds读文件描述符集 // FD_ZERO(rfds); // 初始化rfds进行清空 // FD_SET(_listensock, rfds); // 还是一样的问题到这里我们设置到内核中了吗没有 // // 因为rfd我们是在局部函数中定义的也就是说rfds变量是在用户栈中开辟的并没有陷入内核 // 关键问题当select返回处理完就绪事件后下一次再次调用select // 你怎么清楚历史上有哪些fd是被你设置添加到rfds中让我们的select继续关心 // 问题的产生原因每次select返回的时候rfds绝大多数情况都会被修改 // 修改成只剩“就绪的fd”当时还没有就绪的fd就会在位图中丢失 // 所以也就是说如果我们只依靠rfds来存放历史所有连接的文件描述符是做不到的 // 所以只靠rfds做不到我们就需要额外借助一个辅助数组来帮我们完整记录服务器历史上所有获取到的连接文件描述符 fd_set rfds; FD_ZERO(rfds); int maxfd defaultfd; // 获取最大文件描述符的值用于select // 1.每次select之前都需要对rfds进行重置 for (int i 0; i nums; i) { if (fd_array[i] defaultfd) { // 两种情况1.当前位置还没有被占用2.当前位置的连接被断开重新置成-1 // 不管是哪种情况都不需要设置到位图中 continue; } FD_SET(fd_array[i], rfds); // 2.最大文件描述符fd时刻是变化的有旧的连接会断开也会出现新的连接 // 如果当前的fd_array[i]大于maxfd则更新maxfd if (maxfd fd_array[i]) { maxfd fd_array[i]; } } // int n select(_listensock-Fd() 1, rfds, nullptr, nullptr, nullptr); Testprintfd(); int n select(maxfd 1, rfds, nullptr, nullptr, nullptr); if (n -1) { // 说明select失败 LOG(LogLevel::ERROR) select error; } else if (n 0) { // 说明超时了如果最后一个参数为nullptr阻塞式select则返回值不会为0 LOG(LogLevel::INFO) time out...; } else { // 其他情况返回值则表示事件已经就绪的个数 LOG(LogLevel::INFO) 有事件就绪了... , n n; // 如果是有一个新连接到来了那么select返回值就是1 // 此时如果没有及时调用accept将连接从全连接队列取出结果就是死循环打印信息。为什么 // 因为针对fd的类型是 监听fd那么其读事件就绪的条件就是全连接队列非空有新连接完成握手 // 如果此时没有及时调用accept将连接从全连接队列取出那么这个就绪条件就是恒成立的select就会一直返回1进行打印信息 HandlerEvent(); // 处理已经就绪的事件 } } _isrunning false; } void HandlerEvent() { InetAddr client; int sockfd _listensock-Accept(client); // 此时accept还会阻塞吗不会等的操作已经在上面的select处理了 if (sockfd 0) { LOG(LogLevel::INFO) get a new link, sockfd: sockfd , client: client.StringAddress(); // 此时我们就成功获取到了新连接问题在于我们此时能直接调用read/recv吗不行 // 我们根本不清楚此时这个新的连接fd对应的读事件有没有就绪 // 如果我们直接调用read/recv和阻塞IO没有任何区别等和拷贝的过程就变成一起的了 // 那我们如何清楚新的连接fd对应的读事件是否就绪呢select // 所以我们需要将获取到的新连接fd存放到我们的辅助数组中进行记录 int pos 0; for (pos 0; pos nums; pos) { if (fd_array[pos] defaultfd) { // 说明当前pos位置是空闲的不管是之前就没有使用还是之前的fd断开连接我们都可以使用这个位置 break; } } if (pos nums) { // 说明整个辅助数组都被占满了说明当前服务器已经达到了连接的上限不能再进行连接了直接放弃连接请求 LOG(LogLevel::WARNING) select server full...; close(sockfd); } else { fd_array[pos] sockfd; } } else { LOG(LogLevel::WARNING) accept error..; } } void Testprintfd() { std::cout fd_array[]: ; for (int i 0; i nums; i) { if (fd_array[i] defaultfd) continue; std::cout fd_array[i] ; } std::cout \r\n; } private: std::unique_ptrSocket _listensock; // 监听套接字 bool _isrunning; // 服务器状态 int fd_array[nums]; // 构建一个用于记录服务器历史上所有连接的fd的辅助数组 // 这里我们直接使用定长数组即可其他容器也可以但是定长数组本身就可以约束服务器的连接数量 };5.3 主函数入口#include SelectServer.hpp int main(int argc, char *argv[]) { if (argc ! 2) { std::cout Usage: argv[0] port std::endl; exit(USAGE_ERR); } uint16_t port std::stoi(argv[1]); // 这里使用了 C11 引入的 std::unique_ptr 智能指针来在堆区创建服务器对象。 // 采用智能指针的核心优势是 RAII资源获取即初始化机制 // 即使服务器在未来运行中抛出异常导致意外退出unique_ptr 也会在出作用域时 // 自动调用 selectServer 的析构函数确保底层的文件描述符等系统资源被安全释放。 std::unique_ptrSelectServer svr std::make_uniqueSelectServer(port); // 调用 Start() 后主线程的代码执行流将进入 selectServer 类内部的 while(true) 死循环。 // 服务器从此刻起正式开始运转持续不断地执行 重置位图 - select等待 - 处理就绪事件 的闭环逻辑。 // 除非收到中断信号如 CtrlC或内部发生致命错误调用 exit()否则程序将永远阻塞运行在此处。 svr-Start(); return 0; }核心代码解读辅助数组 fd_array 的作用fd_array是 select 服务的核心。它完整保存全部需要监听的文件描述符包含监听 socket 以及所有客户端连接 socket。 因为 select 调用后fd_set会被内核修改仅保留就绪 fd未就绪的 fd 会从位图丢失。所以每次调用 select 之前必须遍历辅助数组重新把所有有效 fd 填充进 fd_set。accept 为什么不会阻塞select 返回就绪事件代表监听套接字上已经有新连接到达。内核的全连接队列中已经存放完成三次握手的连接此时调用 accept 会立刻拿到连接不会阻塞等待。新连接的处理逻辑成功获取新连接sockfd之后将这个 fd 存入fd_array空闲位置。下一轮循环构建 fd_set 的时候这个新 fd 会被加入监听集合select 就会监听该客户端 fd 上的读事件。5.4 编译与运行编译代码后执行程序时传入端口号启动服务./select_server 8080启动后服务监听 8080 端口可以使用 telnet 或者 nc 工具发起 TCP 连接测试服务接收新连接的能力。当前版本仅支持建立连接后续章节继续扩展客户端数据读写完成 Echo 回声功能。结束语到这里我们完成了 select IO 多路复用的原理讲解与 Echo 服务端实战。我们从多路转接 “等待与拷贝分离” 的核心本质出发完整拆解了 select 函数的参数、返回值与三种等待模式并且动手实现了可运行的 select 服务端代码。select 作为 IO 多路复用的经典实现让我们直观感受到单线程同时监听多个文件描述符的能力同时也能体会到它本身存在的一些性能短板。这些局限性也正是 poll、epoll 诞生的原因。下一篇我们将对本篇文章的 Echo 服务器继续优化补充完成基于 select 的 Echo 服务器之后我们会继续学习 poll对比它和 select 的异同并且进一步对我们 Echo 服务器修改成基于 poll 的实现。掌握好 select 的底层逻辑会帮助我们更容易理解后续更高级的多路复用方案。

相关新闻

文档站信息架构设计:让核心事实稳定出现在页面中

文档站信息架构设计:让核心事实稳定出现在页面中

很多文档站在内容不断增加后,会出现一个典型问题:页面数量越来越多,但用户和解析工具却越来越难找到基础信息。原因通常不在于内容太少,而在于内容被分散在导航、弹窗、图片、异步接口和多层跳转中。重要信息没有固定位置&#xf…

2026/9/30 7:22:17 阅读更多 →
手机芯片峰值性能卷到头了,今年的真战场在日常使用区间上

手机芯片峰值性能卷到头了,今年的真战场在日常使用区间上

制程进入2nm之后,旗舰SoC的竞争逻辑也在发生变化。先进制程能够提供更高的性能上限,但如何把这部分红利转化为更宽的高能效区间,才真正考验芯片设计能力。从现有测试结果看,天玑 9600 Pro 并没有只把重心放在极限频率,…

2026/9/30 7:22:17 阅读更多 →
类和对象(四)

类和对象(四)

在 C 的面向对象编程中,构造函数是每个类都绕不开的核心话题。它负责在对象创建时完成初始化,是对象生命周期中第一个被调用的成员函数。本文将继续深入探讨构造函数的进阶用法——初始化列表,并进一步讲解类型转换与 static 成员这两个与对象…

2026/9/30 7:22:17 阅读更多 →

最新新闻

Linux软硬链接本质:inode与路径的底层原理

Linux软硬链接本质:inode与路径的底层原理

1. 为什么软硬链接不是“复制”,而是“指针”——从文件系统底层讲清楚你有没有试过用ln命令创建一个链接,结果发现删掉源文件后,软链接打不开、硬链接还能访问?或者反过来,改了软链接指向的文件,硬链接却毫…

2026/9/30 7:56:32 阅读更多 →
Linux软链接与硬链接的本质区别及实战应用

Linux软链接与硬链接的本质区别及实战应用

1. 为什么软链接和硬链接不是“差不多就行”的替代品?在Linux系统里,软链接(symbolic link)和硬链接(hard link)常被新手统称为“快捷方式”,但这种类比会埋下严重隐患。我刚入行时就吃过亏&…

2026/9/30 7:56:32 阅读更多 →
SAP S/4HANA部署方式选择实战决策指南

SAP S/4HANA部署方式选择实战决策指南

简介:本资源是一份面向SAP系统实施顾问、云架构师及企业数字化转型从业者的S/4HANA云部署方式深度解析文档,聚焦SAP官方当前主流的四种部署模型及其业务定位差异,有效解决企业在上云路径选择中的决策困惑。文档以清晰对比方式展开&#xff1a…

2026/9/30 7:56:32 阅读更多 →
uni-app 登录页 UI 精修:从背景层到页面栈的细节实战

uni-app 登录页 UI 精修:从背景层到页面栈的细节实战

uni-app 里给微信小程序做登录页面,第一版基本都停留在“能用”的阶段:一个 logo、两个输入框、一个按钮,收工。等产品拿着竞品截图走过来,说一句“这个登录页面 UI 好看,你照着改一下”,很多人才发现自己在…

2026/9/30 7:56:32 阅读更多 →
uni-app微信小程序登录页:Vue3纯CSS高转化UI实战

uni-app微信小程序登录页:Vue3纯CSS高转化UI实战

做小程序登录页这件事,我前后推倒重来过至少七个版本。第一版是照着教程堆出来的深色背景配白色输入框,自认为挺"高级",结果上线一周后后台数据显示登录页跳出率接近四成;第二版换了配色,数据没动&#xff1…

2026/9/30 7:56:32 阅读更多 →
拆开这个环:优化 RAG 通道,解开 SEO 与 GEO 的死循环

拆开这个环:优化 RAG 通道,解开 SEO 与 GEO 的死循环

摘要:GEO 没有标准,它只是 RAG 的引用打分回路。这个回路正在反向磨平人类内容:RLHF 把 AI 磨成平均值,GEO 再让人类照着这个平均值生长,两个平均化首尾相接,咬成死循环。解法不是拒绝 AI,也不是…

2026/9/30 7:55:32 阅读更多 →

日新闻

Base64 图片头部特征识别:从文件头到格式判断的完整指南

Base64 图片头部特征识别:从文件头到格式判断的完整指南

1. 项目概述:为什么说看懂 base64 图片头部是基本功这几年跟 base64 打交道的机会越来越多,后端接口返回图片、前端渲染验证码、小程序里存小图、还有一些老系统导出报表,动不动就给你一段长到怀疑人生的 base64 字符串。很多人拿到字符串就直…

2026/9/30 0:00:35 阅读更多 →
Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

Java公交站牌广告管理系统:JSP+Servlet+MySQL实战落地指南

简介:本资源是一份面向Java初学者与课程设计学生的公交站牌广告灯箱管理系统毕业设计文档,聚焦城市公共广告资源信息化管理痛点,提供从需求分析到技术实现的完整方案。文档采用标准学术论文结构,含摘要、英文摘要、目录及五章正文…

2026/9/30 0:00:35 阅读更多 →
用 Redis Lua 构建大模型 API 多租户原子配额治理体系

用 Redis Lua 构建大模型 API 多租户原子配额治理体系

我去年年底接了一个内部 AI 平台的治理需求,背景很直接:公司把 DeepSeek、MiniMax 这类大模型 API 统一封装成内部网关,开放给几个业务团队用。结果第一个月账单出来,额度直接超了 4 倍。仔细查日志,发现原因并不复杂—…

2026/9/30 0:00:35 阅读更多 →

周新闻

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解

如何划分训练/验证集:Spirula Studio五种eval_mode策略详解 【免费下载链接】spirula-studio Cross-vendor 3D Gaussian Splatting trainer - video to splat to mesh, Vulkan or CUDA. 项目地址: https://gitcode.com/GitHub_Trending/sp/spirula-studio Sp…

2026/9/29 8:16:59 阅读更多 →
SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南

SEO怎么推广速查手册新手避坑实战指南 模板网站太丑不够用?别急着加滤镜,那是治标不治本。很多老板盯着后台流量掉得眼红,却还在纠结首页Banner的圆角是不是3像素。这就像穿着西装去挖土,姿势不对,努力白费。我整理这份 速查手册…

2026/9/29 16:41:41 阅读更多 →
FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏

FireRed-OpenStoryline少样本仿写深度解析:AI Agent如何复刻你的独特文案风格与节奏 【免费下载链接】FireRed-OpenStoryline FireRed-OpenStoryline is an AI video editing agent that transforms manual editing into intention-driven directing through natural language …

2026/9/29 8:24:48 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/29 19:29:29 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/29 5:58:00 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/29 3:55:56 阅读更多 →