面试宝典(十六):io_uring 真异步实战
0. 为什么需要 io_uring传统 Linux 异步 I/Oio_submit/aio只能用于直接 I/OO_DIRECT的文件且 API 丑陋、对网络支持差。网络高并发长期依赖 epoll但 epoll 有两个本质痛点每次 I/O 仍要一次系统调用。epoll_wait告诉你可读你还是要recv要写又得send。一次请求往往伴随多次陷入内核。中断驱动。epoll_wait默认阻塞在中断上高吞吐下中断开销明显。2019 年内核 5.1 由 Jens Axboe 引入io_uring核心思想是用两个内核与用户态共享内存的环形队列ring buffer彻底消灭每 I/O 一次 syscall 的开销Submission Queue (SQ)用户态生产、sqesubmission queue entry描述一个 I/O 请求内核消费。Completion Queue (CQ)内核生产、cqecompletion queue entry描述完成结果用户态消费。因为 SQ/CQ 是mmap出来的共享内存用户态填 sqe、读 cqe 都不需要系统调用只有在需要让内核注意到新请求、或等待完成时才调用一次io_uring_enterliburing 封装为io_uring_submit/io_uring_wait_cqe。1. 核心数据结构用户态 内核态 ┌──────────────┐ ┌──────────────────┐ │ sqe (请求) │ 提交环(SQ) │ 内核处理 │ │ → SQ ring │ ──────────▶ │ │ │ (下标数组) │ │ │ │ │ │ │ │ cqe (结果) │ 完成环(CQ) │ │ │ ← CQ ring │ ◀────────── │ 内核写入结果 │ └──────────────┘ └──────────────────┘sqe一次 I/O 操作的完整描述包含opcode操作类型、fd、buf、len、off、user_data用户自定义令牌用来把完成和提交对应起来、flags等。SQ ring一个下标数组里面存的是哪些 sqe 槽位被使用了。这样 sqe 本身可以非连续存放SQ ring 只是索引。cqeuser_datares结果类似 read 的返回值负数表示 errnoflags。user_data 是关键你提交 N 个请求完成时顺序不一定和提交顺序一致尤其异步、乱序设备必须靠user_data把 cqe 关联回你的连接/请求上下文。liburing 帮我们封装了底层io_uring_setupmmap暴露简洁 API。2. 最小上手搭建 ring#includeliburing.h#includestdio.hintmain(){structio_uringring;// 第二个参数: SQ 队列深度可同时提交的请求数// 0: 默认 flagsintretio_uring_queue_init(32,ring,0);if(ret0){fprintf(stderr,io_uring_queue_init: %s\n,strerror(-ret));return1;}// ... 提交 I/O ...io_uring_queue_exit(ring);// 释放return0;}io_uring_queue_init(entries, ring, flags)内部调用io_uring_setup并mmap出 SQ/CQ。返回负值绝对值是 errno表示失败常见于内核过旧 5.1或io_uring_setup被 seccomp/容器限制。3. 一次完整读提交与收割#includeliburing.h#includeunistd.h#includestring.h// 提交一个异步读staticvoidsubmit_read(structio_uring*ring,intfd,char*buf,size_t len,void*ud){structio_uring_sqe*sqeio_uring_get_sqe(ring);// 取一个空闲 sqeif(!sqe){/* SQ 满了需先收割 */}io_uring_prep_read(sqe,fd,buf,len,0);// 准备 read 操作io_uring_sqe_set_data(sqe,ud);// 绑定 user_dataio_uring_submit(ring);// 提交必要时 io_uring_enter}// 收割完成staticvoidreap(structio_uring*ring){structio_uring_cqe*cqe;// io_uring_wait_cqe: 阻塞等至少一个完成io_uring_wait_cqe(ring,cqe);// 批量收割所有已就绪 cqe更高效unsignedhead;io_uring_for_each_cqe(ring,head,cqe){void*udio_uring_cqe_get_data(cqe);intrescqe-res;// 读到的字节数负数错误printf(完成 fd 相关%p 读到%d 字节\n,ud,res);}io_uring_cq_advance(ring,/*已处理数量*/0);// 见下方注意}两个极易踩的坑io_uring_get_sqe返回 NULL 表示 SQ 满了。生产代码必须先io_uring_submit或io_uring_peek_cqe收割腾出空间再取 sqe。收割批量 cqe 后必须用io_uring_cq_advance(ring, count)告诉内核这 count 个 cqe 我处理完了内核才能复用 CQ 槽位。io_uring_for_each_cqe本身不消费只遍历。若只处理一个可用io_uring_cqe_seen(ring, cqe)。4. 模式SQPOLL 与 IOPOLLio_uring 的性能主要来自三种io_uring_setupflag传给io_uring_queue_init的第三个参数flag作用代价IORING_SETUP_IOPOLL让内核轮询设备完成而不是等中断。仅对支持轮询的文件如 NVMe、O_DIRECT有效占 CPU但延迟极低IORING_SETUP_SQPOLL内核起一个内核线程轮询 SQ用户态提交后连io_uring_enter都不用调用需要CAP_SYS_NICE或合适权限空闲会睡眠IORING_SETUP_SQ_AFF配合 SQPOLL绑定轮询线程到某 CPU—structio_uringring;unsignedflagsIORING_SETUP_SQPOLL;// 提交零 syscallio_uring_queue_init(256,ring,flags);// 之后 io_uring_submit 在 SQPOLL 模式下可省去 enter面试要点IOPOLL 针对完成侧不要中断SQPOLL 针对提交侧不要 enter syscall。两者叠加可做到提交与收割都几乎零系统调用这是 io_uring 碾压 epoll 的根本原因。但 CPU 占用高适合追求极限延迟、设备支持轮询的场景。普通网络场景用默认模式 批量收割已收益显著。5. 操作码opcode全景liburing 提供io_uring_prep_*系列为常见操作填 sqeio_uring_prep_accept—— 异步 acceptio_uring_prep_recv/io_uring_prep_send—— 网络收/发支持MSG_WAITALL等 flagio_uring_prep_read/io_uring_prep_write—— 文件/管道io_uring_prep_readv/io_uring_prep_writevio_uring_prep_timeout—— 异步超时用来实现定时器io_uring_prep_close—— 异步关闭 fdio_uring_prep_nop—— 空操作测试/占位io_uring_prep_connect/io_uring_prep_poll_add/io_uring_prep_fsync/io_uring_prep_openat等关键能力io_uring 把 accept、recv、send、甚至文件 open、fsync、timeout 都统一成提交一个 sqe用同一套完成机制处理。这就是它统一事件源的魅力——网络连接、定时器、磁盘 I/O 全在一个 ring 里调度。6. 链式请求linked sqe有时需要先 recv 拿到数据再 send 同样的数据回去两步必须顺序。用sqe-flags | IOSQE_IO_LINK把多个 sqe 链起来前一个完成才提交下一个前一个失败则后续整条取消。structio_uring_sqe*sqe1io_uring_get_sqe(ring);io_uring_prep_recv(sqe1,fd,buf,len,0);sqe1-flags|IOSQE_IO_LINK;// 链接到下一条structio_uring_sqe*sqe2io_uring_get_sqe(ring);io_uring_prep_send(sqe2,fd,buf,len,0);// sqe2 会等 sqe1 完成才执行io_uring_submit(ring);链式请求可减少收割→再提交的往返特别适合 echo 这类收完即发的场景。7. 注册缓冲区与文件registered buffers / files默认每次 I/O内核要把用户态 buf 锁定pin进内核地址空间这本身有开销。io_uring 允许预先注册一组 buffer 和一组 fdio_uring_register_buffers(ring, iovecs, n)—— 内核一次性 pin 住这些 buffer之后 I/O 用时指定buf_index免去每次 pin。io_uring_register_files(ring, fds, n)—— 把 fd 在内核里固定编号sqe 用sqe-fd 固定编号并设IOSQE_FIXED_FILE省去 fd 查找。这进一步优化了极限吞吐。生产服务器如现代 Redis/Velocity 类会结合注册 buffers 提升性能。8. 实战io_uring 高并发回声服务器完整可编译需要g -stdc17 server.cpp -luring内核 5.1#includeliburing.h#includesys/socket.h#includenetinet/in.h#includearpa/inet.h#includeunistd.h#includestring.h#includestdio.h#includestdlib.h#defineENTRIES1024#defineBUF_SIZE4096// 每个连接的上下文buffer fdstructConn{intfd;charbuf[BUF_SIZE];};staticvoidsubmit_accept(structio_uring*ring,intlisten_fd);staticvoidsubmit_recv(structio_uring*ring,Conn*c);intmain(){intlisten_fdsocket(AF_INET,SOCK_STREAM,0);intone1;setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,one,sizeof(one));structsockaddr_inaddr{};addr.sin_familyAF_INET;addr.sin_porthtons(8080);addr.sin_addr.s_addrINADDR_ANY;bind(listen_fd,(sockaddr*)addr,sizeof(addr));listen(listen_fd,1024);structio_uringring;io_uring_queue_init(ENTRIES,ring,0);submit_accept(ring,listen_fd);// 先挂一个 acceptstructio_uring_cqe*cqe;while(true){io_uring_wait_cqe(ring,cqe);// 等完成void*udio_uring_cqe_get_data(cqe);if(udnullptr){// 这是我们约定的user_datanullptr 表示 accept 完成intconn_fdcqe-res;// accept 的返回值就是新 fdif(conn_fd0){Conn*cnewConn{conn_fd,{}};submit_recv(ring,c);// 立即为新连接提交 recv}submit_accept(ring,listen_fd);// 再挂下一个 accept}else{Conn*c(Conn*)ud;intrescqe-res;// recv 读到的字节数if(res0){// 回显把刚读到的内容 send 回去structio_uring_sqe*sqeio_uring_get_sqe(ring);io_uring_prep_send(sqe,c-fd,c-buf,res,0);io_uring_sqe_set_data(sqe,c);io_uring_submit(ring);submit_recv(ring,c);// 继续等下一次 recv}else{// res0 对端关闭 / 负数出错清理close(c-fd);deletec;}}io_uring_cqe_seen(ring,cqe);// 标记该 cqe 已处理}io_uring_queue_exit(ring);return0;}staticvoidsubmit_accept(structio_uring*ring,intlisten_fd){structio_uring_sqe*sqeio_uring_get_sqe(ring);io_uring_prep_accept(sqe,listen_fd,nullptr,nullptr,0);io_uring_sqe_set_data(sqe,nullptr);// nullptr 代表 acceptio_uring_submit(ring);}staticvoidsubmit_recv(structio_uring*ring,Conn*c){structio_uring_sqe*sqeio_uring_get_sqe(ring);io_uring_prep_recv(sqe,c-fd,c-buf,BUF_SIZE,0);io_uring_sqe_set_data(sqe,c);// 绑定连接上下文io_uring_submit(ring);}注意这是教学骨架。生产级需要处理io_uring_get_sqe返回 NULL满了先收割、 SQ 满时背压、优雅退出信号、链接 recv→send 用IOSQE_IO_LINK、错误处理cqe-res 0。但核心套路已经完整一个 ring所有 accept/recv/send 都是 sqe一个循环收割 cqe 并据user_data分发。9. io_uring vs epoll面试怎么答维度epollio_uring模型就绪通知reactor异步完成proactor 风格每次 I/O 系统调用需要recv/send不需要提交即走完成入队提交侧开销无但需 waitSQPOLL 下零 syscall磁盘 I/O不支持 AIO 文件原生支持且统一定时器/信号处理需 timerfd/signalfdIORING_OP_TIMEOUT原生内核版本2.5.44 全平台5.1新特性逐版增强复杂度心智简单API/概念更多一句话总结epoll 是我告诉你 fd 就绪了你自己去读io_uring 是你把读请求交给我读完了我通知你结果。前者是 reactor后者更接近 proactor且把网络、磁盘、定时器统一进同一个事件循环这是它架构上的最大优势。10. 速答 12 题临场背诵io_uring 两个环分别叫什么、谁生产谁消费SQ用户生产、内核消费放请求CQ内核生产、用户消费放结果。为什么 io_uring 比 epoll 快SQ/CQ 是共享内存提交与完成都可免去每 I/O 一次 syscallSQPOLL/IOPOLL 进一步消除 enter 与中断。sqe 和 cqe 区别sqe 描述要做什么 I/Ocqe 描述做完了结果如何。user_data 干嘛用把完成结果关联回提交时的连接/请求上下文因为异步完成顺序不保证。IORING_SETUP_SQPOLL 作用内核起线程轮询 SQ用户态提交无需io_uring_entersyscall。IORING_SETUP_IOPOLL 作用内核轮询设备完成代替中断降低设备 I/O 延迟需设备支持。sqe 返回 NULL 怎么办SQ 满了先收割/提交已有 sqe 腾空间再取。为什么要 io_uring_cq_advance告诉内核这批 cqe 已处理内核才能复用 CQ 槽位。IOSQE_IO_LINK 是什么把多个 sqe 链接成顺序链前一完成才做下一失败则整链取消。注册 buffer/file 有何用预先 pin 住内存/固定 fd免去每次 I/O 的 pin 与查找开销极限优化。io_uring 能做定时器吗能IORING_OP_TIMEOUT原生支持无需 timerfd。最低内核版本5.12019后续版本不断增强 opcode 与特性。11. 临场口诀SQ 交请求CQ 收结果user_data 定归属cq_advance 别忘还SQPOLL 免 enterIOPOLL 免中断epoll 是就绪通知io_uring 是真异步。12. 实战踩坑清单高频sqe 用尽io_uring_get_sqe返回 NULL 时若继续写会段错误。正确做法是在主循环里先收割再取 sqe或预留 back-pressure 机制。生产服务器常把SQ 满了当作需要放慢提交的信号。忘记cqe_seen/cq_advanceCQ 槽位永不回收跑一会儿 CQ 满io_uring_wait_cqe无限阻塞。务必每处理完一个 cqe 就seen批量就cq_advance。user_data 悬空指针cqe-user_data指向你在 sqe 提交时绑的对象。如果该对象在 I/O 未完成前被delete完成回来访问的是野指针。务必保证上下文生命周期覆盖整个异步周期常见做法引用计数或完成时才释放。SQPOLL 权限问题容器里常因缺CAP_SYS_NICE导致io_uring_queue_init失败返回-EPERM。此时退化到默认模式即可不要硬编码 SQPOLL。内核版本特性差异IORING_OP_ACCEPT在 5.5IORING_OP_RECV/SEND在 5.6IORING_OP_TIMEOUT在 5.11。编译期用io_uring_opcode_supported探测更稳。buffer 生命周期sqe 里的buf/iovec在 I/O 完成前必须一直有效不能提交后立即释放局部数组。13. 真实落地与版本演进io_uring 已被众多高性能项目采用或试验数据库/存储RocksDB、TiKV 等引入 io_uring 后端提升写吞吐PostgreSQL 社区也有 io_uring 补丁讨论。网络/代理现代高性能代理、gRPC 实验性 io_uring 传输、Envoy 相关探索。Redis 7引入 io_uring 线程池后端选项io_threads 的替代/补充。fioJens Axboe 自己的工具最早吃螃蟹io_uring 引擎性能远超 libaio。演进方向io_uring 正逐步统一 Linux 异步 I/O把网络、磁盘、定时器、信号、文件操作收进一个原语。C 生态里liburing是事实标准封装Boost.Asio 也通过boost::asio::io_uring实验性支持。面试若被问未来异步 I/O 趋势答 io_uring 的统一事件源 真异步 共享内存零 syscall即可体现视野。14. 一个可亲手跑的 perf 对照思路想直观感受 io_uring 收益用 S03 的 perf 方法对 epoll 回声服务器与 io_uring 回声服务器各跑perf stat -e syscalls:sys_enter_*压测你会看到 io_uring默认模式的 syscall 次数明显少于 epoll因为少了 recv/send 陷入若开 SQPOLL 则io_uring_enter也大幅下降。这种用工具量化差异的思路正是中高级工程师区别于初学者的地方。15. io_uring 与 Reactor / Proactor 模型计算机网络里两种经典异步模型Reactor反应堆你注册我对 fd 可读感兴趣事件循环通知你现在可读了然后你自己去读。epoll 是典型的 Reactor。好处是心智简单、控制力强坏处是读写仍占用户态 CPU 且要 syscall。Proactor前摄器你提交帮我读完这块缓冲区事件循环在操作真正完成后通知你数据已经在你的 buffer 里了。io_uring 天然是 Proactor 风格——你提交 sqe内核把数据搬好cqe 带着结果回来。但注意一个细节io_uring 也可以模拟 Reactor——用IORING_OP_POLL_ADD提交一个等 fd 可读的请求完成时再提交真正的 recv。所以 io_uring 既能 Proactor 也能 Reactor灵活性极高。这也是为什么很多框架如 tokio、glommio选择 io_uring 作为统一后端。16. io_uring 线程池混合架构单线程跑 ring 的事件循环主 Reactor负责 accept/recv/send 等 I/O当某请求需要重计算如压缩、序列化、业务规则时把该任务submit进线程池见 S06算完再把结果通过另一个 sqe 发回客户端。这样 I/O 不被 CPU 密集任务阻塞是典型的高性能服务器架构。伪流程主循环wait_cqe→ 若是计算完成的 cqe用独立user_data标记取出线程池结果 → 提交IORING_OP_SEND把结果写回若是收到请求的 cqe则把解析后的任务丢进线程池。这种事件循环 线程池卸载组合在 S01epoll、S05io_uring、S06线程池三篇里形成闭环。17. 内核参数与线上限制/proc/sys/fs/aio-max-nr虽然 io_uring 不用老 aio但某些发行版仍相关io_uring 自身限制由io_uring_setup的IORING_FEAT_*特性位决定。SQPOLL 内核线程会常驻一个内核线程轮询空闲一段时间默认会自行休眠省 CPU可通过IORING_SETUP_SQ_AFF绑核。容器/受限环境可能禁止需 try 默认模式 fallback。每进程 ring 数量理论上限受RLIMIT_MEMLOCK/mmap配额影响因为 SQ/CQ 是锁页内存。大量短命 ring 会触发内存上限应复用长生命周期 ring。提交深度entries太小会频繁 SQ 满太大浪费内存根据并发连接数与 I/O 在途量评估常见 1024~4096。理解这些限制才能在面试里把io_uring 很快讲成在哪些条件下、受到哪些约束、如何调优而不是一句空话。18. 速查io_uring opcode 与 flag 全表常用 opcode提交请求的动作opcode含义典型场景IORING_OP_NOP空操作测试、占位IORING_OP_READ/WRITE文件读/写磁盘 I/OIORING_OP_READV/WRITEV分散/聚集读写多段缓冲区IORING_OP_RECV/SEND网络收/发TCP 回声IORING_OP_ACCEPT接受连接服务器监听IORING_OP_CONNECT发起连接客户端IORING_OP_POLL_ADD注册 fd 等待事件模拟 ReactorIORING_OP_TIMEOUT异步超时定时器IORING_OP_CLOSE异步关闭 fd清理连接IORING_OP_FSYNC/FSYNC刷盘持久化IORING_OP_OPENAT打开文件文件服务IORING_OP_SPLICE/LINKAT零拷贝拼接代理转发常用 setup flag队列创建选项flag作用适用IORING_SETUP_SQPOLL内核线程轮询 SQ免 enter syscall极限提交吞吐IORING_SETUP_IOPOLL内核轮询设备完成免中断NVMe/DIRECTIORING_SETUP_SQ_AFFSQPOLL 绑核稳定延迟IORING_SETUP_CQSIZE自定义 CQ 大小深度调优IORING_SETUP_CLAMP限制内核参数上限安全约束环境把这张表记熟面试官随便问一个 opcode 你都能接住并且能讲清每个 flag 的代价与适用条件——这才是深度的体现而非只背过io_uring 很快。19. 临场自检三问 io_uring自测你是否真懂 io_uring能答出以下三点即可过关“io_uring 怎么做到比 epoll 少系统调用”—— SQ/CQ 是内核用户共享内存提交填 sqe、收割读 cqe 都不 syscallSQPOLL 进一步免去 enterIOPOLL 免去中断所以提交零 syscall、完成零中断。“异步完成顺序乱了怎么办”—— 靠user_data把 cqe 关联回提交时的连接上下文完成顺序不保证绝不能用数组下标假设对应。“为什么 io_uring 能统一网络、磁盘、定时器”—— 所有操作都被抽象成 sqeaccept/recv/send/read/write/timeout/close…统一由 ring 调度完成这就是统一事件源架构优势而 epoll 只管网络就绪。能流畅讲清这三点io_uring 这一题基本拿下。本篇所有代码均建议在你本地内核 5.1 以上的机器上用g -stdc17 server.cpp -luring实际编译运行并用perf trace观察io_uring_enter的调用频次把看懂真正变成会写、会调、会量化这才是中高级面试想要的真实动手能力。

相关新闻

面试宝典(十七):手写线程池与定时器

面试宝典(十七):手写线程池与定时器

0. 为什么需要线程池 每次任务来都 std::thread 新建线程的代价: 创建成本高:内核要分配 PCB、栈、调度结构,约几十~上百微秒。数量失控:突发流量下线程数爆炸,上下文切换(context switch)开销反…

2026/8/18 19:24:32 阅读更多 →
计算机毕业设计之钢铁生产系统的设计与实现

计算机毕业设计之钢铁生产系统的设计与实现

随着网络科技的不断发展以及人们经济水平的逐步提高,网络技术如今已成为人们生活中不可缺少的一部分,而信息管理系统是通过计算机技术,针对用户需求开发与设计,该技术尤其在各行业领域发挥了巨大的作用,相比于以前的传…

2026/8/18 19:23:32 阅读更多 →
Python时间处理全解析:从time模块到datetime时区转换实战

Python时间处理全解析:从time模块到datetime时区转换实战

1. 项目概述:Python时间处理的基石 在任何一个涉及数据记录、任务调度、日志分析或者用户交互的Python项目中,时间处理都是一个绕不开的基础环节。无论是记录一条数据的创建时间,计算一个函数的执行耗时,还是将数据库里的一串数字…

2026/8/18 19:23:32 阅读更多 →

最新新闻

QUICK:GPU 加速的 ab initio / DFT 开源量子化学包—原理、安装实测与横向对比

QUICK:GPU 加速的 ab initio / DFT 开源量子化学包—原理、安装实测与横向对比

QUICK 是 UCSD Gtz Lab 与 Michigan State Merz Lab 联合开发的开源量子化学包,主打 GPU-native HF / DFT 计算、MPI 多卡扩展、内置 QM/MM 接口(与 AmberTools 26 直接集成)。专注于 HF/DFT 计算、几何优化、RESP 电荷和 QM/MM 模拟。最新版本 QUICK-26.03(2026-07-25)已…

2026/8/18 20:39:10 阅读更多 →
九种天气下的蓝调通勤:亚洲成年女性高清提示词实验

九种天气下的蓝调通勤:亚洲成年女性高清提示词实验

封面只负责建立系列节奏;正文保留九张独立高清竖图。 摘要| 同样是蓝色,春雨、干雷雨、海雾、轻雪、太阳雨、季风、秋风、霜冻和雨后蓝调会给面料完全不同的亮度与情绪。本组用九位约 22 岁亚洲成年女性、九种面孔与焦段,完成 5 套…

2026/8/18 20:39:10 阅读更多 →
AI 查库为什么要先做权限交集,再让模型看 Schema?

AI 查库为什么要先做权限交集,再让模型看 Schema?

先确定谁能看什么,再让模型生成 SQL;顺序本身就是安全边界。 摘要| 把数据库结构整包交给模型,再对生成 SQL 做一次关键词过滤,看起来省事,实际上把越权风险提前送进了提示词。本文结合 Microi吾码AI 当前 …

2026/8/18 20:39:10 阅读更多 →
干货:18 张思维导图,后端技术学习路线长这样!

干货:18 张思维导图,后端技术学习路线长这样!

1946年, 世界上第一台名叫「ENIAC」的通用计算机被发明出来, 它正如其名字那般仅仅是用来计算的。后来, 计算机数量变得越来越多起来, 当没有网络的时候, 每一台计算机都将会变成一个孤岛, 如此也就不会有如今互联网的那种繁荣景象了。「计算机网络」这门课程的学习路线是极为清…

2026/8/18 20:39:10 阅读更多 →
利用多台老旧笔记本搭建分布式集群,低成本本地部署800亿参数大模型

利用多台老旧笔记本搭建分布式集群,低成本本地部署800亿参数大模型

这次我们来看一个非常硬核的本地AI部署方案:用多台老旧笔记本搭建一个分布式计算集群,来运行参数量高达800亿(80B)的大语言模型。这个项目的核心思路不是追求单卡的极致性能,而是通过资源整合,让那些被淘汰…

2026/8/18 20:39:10 阅读更多 →
重构复杂条件逻辑:状态模式与策略模式实战

重构复杂条件逻辑:状态模式与策略模式实战

1. 为什么我们需要重构if/switch语句在代码维护过程中,我们经常会遇到这样的场景:一个方法里嵌套着七八层if判断,或者一个switch语句横跨上百行代码。这种代码结构不仅难以阅读和维护,还会带来一系列实际问题。我最近接手的一个电…

2026/8/18 20:38:09 阅读更多 →

日新闻

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 如果你还停留在"看网课 不停暂停 截图 …

2026/8/18 0:00:57 阅读更多 →
思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 你是不是也经历过这种时刻:设计稿里…

2026/8/18 0:00:58 阅读更多 →
华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, …

2026/8/18 0:00:59 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/18 9:15:35 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/18 9:06:28 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/18 9:04:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/17 18:54:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/17 18:55:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/17 18:55:55 阅读更多 →