Linux高性能定时器:timerfd与epoll事件循环实战

1. 为什么需要把 timerfd 和 epoll 放在一起用

做 Linux 后台服务开发的人,迟早会碰到一个绕不开的问题:一个进程要同时处理网络 IO、信号、定时任务,怎么把它们统一管起来。早期大家用alarm()或者setitimer()配信号处理,写起来简单,但坑特别多——信号处理函数里能做的事情有限,多线程环境下信号投递到哪个线程完全不可控,定时精度也一般。后来有人用select()的超时参数做定时,但那个超时精度只有微秒级且每次都要重新设置,混在 IO 逻辑里非常别扭。

timerfd是 Linux 2.6.25 之后引入的一套机制,它把定时器变成了一个文件描述符。这个转变非常关键:一旦定时器变成了 fd,它就能和 socket、pipe、eventfd 一样被epoll统一监听。整个事件循环里只需要一个epoll_wait(),网络事件和定时事件从同一个出口出来,代码结构一下子清爽了。这也是为什么现在很多高性能服务框架,底层事件循环都是"epoll + timerfd + eventfd"这套组合。

这篇文章面向的是已经会写基本 socket 程序、想把自己的事件循环做得更规范的开发者。我会从设计思路讲到完整可运行的代码,再把实际调试中踩过的坑一个个摊开说。看完你应该能直接把这套东西搬进自己的项目里,而不是停留在"知道有这么个东西"的阶段。

需要提前说明的是,timerfd是 Linux 特有的,BSD 和 Windows 上没有对应实现,跨平台项目要自己做一层抽象。另外它依赖epoll或者poll来发挥价值,单独用虽然也能read()阻塞等待,但那就失去意义了。

2. 整体设计思路与方案选型

2.1 定时器方案横向对比

在动手写代码之前,先把几种常见定时方案摆在一起比一比,这样你能清楚知道为什么最后选timerfd。

方案精度与 epoll 集成多线程友好主要缺点
alarm()/setitimer()微秒级差,靠信号差信号处理受限,易丢失
select()超时微秒级一般一般每次重设,fd 数量受限
epoll_wait()超时毫秒级原生好只能有一个超时,粒度粗
时间轮(用户态)毫秒级需自己驱动好实现复杂,需配合 tick
timerfd纳秒级原生好仅 Linux

从表里能看出来,timerfd在精度和集成度上是综合最优的。epoll_wait()自带的超时参数虽然也能做定时,但它本质上只有一个"最近到期时间",如果你有十个不同周期的任务,就得自己维护最小堆,每次算最近的那个,代码量并不比直接用timerfd少,而且精度只有毫秒。

2.2 核心设计:一个 fd 就是一个定时器

timerfd的设计哲学很朴素:创建一个定时器,返回一个 fd;定时器到期时,这个 fd 变成可读;你read()它,读到一个 8 字节的uint64_t,表示从上一次读取到现在一共到期了多少次。

这个"到期次数"的设计很巧妙。假设你的定时器周期是 10ms,但某次事件循环被一个耗时操作卡了 55ms,那么下次read()会返回 5,告诉你"这期间到期了 5 次"。你可以选择把这 5 次合并处理(大多数场景够用),也可以循环处理 5 次(需要精确计数的场景)。这个信息如果用信号或者select超时是拿不到的,它们只会告诉你"超时了",丢了多少次完全不知道。

2.3 为什么用 epoll 而不是 poll

poll也能监听timerfd,功能上没问题。但epoll有两个实际优势:一是 fd 数量大时性能不退化,poll是 O(n) 遍历;二是epoll支持边缘触发(ET)模式,配合非阻塞 fd 能减少不必要的系统调用。对于一个要长期运行、可能管理成百上千个连接的服务来说,epoll是更稳妥的选择。下面所有代码都基于epoll的**水平触发(LT)**模式,因为 LT 模式下timerfd的处理逻辑更直观,不容易漏读。

提示:如果你打算用 ET 模式,timerfd的 fd 必须设成非阻塞,并且read()要循环读到EAGAIN为止,否则会丢事件。新手建议先用 LT 把逻辑跑通。

3. 核心 API 细节与参数解析

3.1 timerfd_create:创建定时器 fd

#include <sys/timerfd.h> int timerfd_create(int clockid, int flags);

clockid有两个常用取值:

  • CLOCK_REALTIME:跟随系统实时时间,受settimeofday()和 NTP 调整影响。适合"每天凌晨 3 点执行"这类挂钟时间相关的任务。
  • CLOCK_MONOTONIC:单调递增,不受系统时间调整影响。适合"每隔 100ms 执行一次"这类间隔型任务。

绝大多数场景应该用CLOCK_MONOTONIC。我见过有服务用CLOCK_REALTIME做心跳定时,结果运维手动校准了一次系统时间,所有定时器集体错乱,心跳包瞬间发了一堆。这个坑不值得踩。

flags常用两个:

  • 0:默认阻塞。
  • TFD_NONBLOCK:非阻塞。配合epoll的 ET 模式时必须加。
  • TFD_CLOEXEC:exec时自动关闭 fd。写库或者长期服务建议加上,避免 fd 泄漏到子进程。

返回值是一个新的 fd,失败返回 -1 并设置errno。

3.2 timerfd_settime:设置定时参数

struct itimerspec { struct timespec it_interval; // 周期间隔 struct timespec it_value; // 首次到期时间 }; int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);

这里有两个字段要分清楚,新手最容易搞混:

  • it_value:第一次到期还有多久。设成 0 表示 disarm(停止定时器)。
  • it_interval:第一次到期之后,每隔多久重复一次。设成 0 表示只触发一次(one-shot)。

所以一个"1 秒后首次触发,之后每 500ms 触发一次"的定时器是这样配的:

struct itimerspec ts; ts.it_value.tv_sec = 1; ts.it_value.tv_nsec = 0; ts.it_interval.tv_sec = 0; ts.it_interval.tv_nsec = 500 * 1000 * 1000; // 500ms timerfd_settime(tfd, 0, &ts, NULL);

flags参数常用0(相对时间)或TFD_TIMER_ABSTIME(绝对时间)。用绝对时间时,it_value表示的是一个绝对的时间点,配合CLOCK_MONOTONIC可以用来做"对齐到整秒"这类需求。

3.3 read:读取到期次数

uint64_t expirations; ssize_t n = read(tfd, &expirations, sizeof(expirations));

必须读满 8 字节。如果缓冲区小于 8 字节,read()会返回EINVAL。这个错误我第一次遇到时排查了半天,因为文档里没特别强调。读到之后expirations就是自上次读取以来的到期次数。

如果定时器还没到期,阻塞模式下read()会挂起,非阻塞模式下返回 -1 且errno为EAGAIN。

3.4 参数计算:纳秒字段的坑

timespec的tv_nsec字段合法范围是[0, 999999999]。如果你想设 1.5 秒,不能写成tv_sec=1, tv_nsec=1500000000,那会返回EINVAL。正确写法是tv_sec=1, tv_nsec=500000000。

写个辅助宏会省事很多:

#define MS_TO_TIMESPEC(ms, ts) do { \ (ts)->tv_sec = (ms) / 1000; \ (ts)->tv_nsec = ((ms) % 1000) * 1000000L; \ } while (0)

4. 完整实操:从零搭一个定时事件循环

4.1 环境准备与编译

这套代码只需要 Linux 内核 2.6.25 以上,glibc 正常安装即可。编译命令:

gcc -o timerfd_demo timerfd_demo.c -Wall -O2

不需要链接额外的库,timerfd的接口都在 glibc 里。如果你用的是 musl libc(比如 Alpine),同样支持,头文件路径一致。

4.2 完整可运行代码

下面这份代码实现了一个事件循环,同时监听一个timerfd(每 500ms 触发)和一个标准输入(用来演示多 fd 混合监听)。你可以直接复制编译运行。

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <stdint.h> #include <sys/epoll.h> #include <sys/timerfd.h> #define MAX_EVENTS 8 static int make_timerfd(long interval_ms, long initial_ms) { int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); if (tfd < 0) { perror("timerfd_create"); return -1; } struct itimerspec ts; memset(&ts, 0, sizeof(ts)); ts.it_value.tv_sec = initial_ms / 1000; ts.it_value.tv_nsec = (initial_ms % 1000) * 1000000L; ts.it_interval.tv_sec = interval_ms / 1000; ts.it_interval.tv_nsec = (interval_ms % 1000) * 1000000L; if (timerfd_settime(tfd, 0, &ts, NULL) < 0) { perror("timerfd_settime"); close(tfd); return -1; } return tfd; } static void handle_timer(int tfd) { uint64_t expirations; ssize_t n = read(tfd, &expirations, sizeof(expirations)); if (n != sizeof(expirations)) { if (errno != EAGAIN) perror("read timerfd"); return; } printf("[timer] fired %llu time(s)\n", (unsigned long long)expirations); } int main(void) { int tfd = make_timerfd(500, 1000); if (tfd < 0) return 1; int epfd = epoll_create1(EPOLL_CLOEXEC); if (epfd < 0) { perror("epoll_create1"); return 1; } struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = tfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, tfd, &ev) < 0) { perror("epoll_ctl timerfd"); return 1; } ev.events = EPOLLIN; ev.data.fd = STDIN_FILENO; if (epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) < 0) { perror("epoll_ctl stdin"); return 1; } struct epoll_event events[MAX_EVENTS]; printf("event loop started, type something and press enter\n"); for (;;) { int n = epoll_wait(epfd, events, MAX_EVENTS, -1); if (n < 0) { if (errno == EINTR) continue; perror("epoll_wait"); break; } for (int i = 0; i < n; i++) { int fd = events[i].data.fd; if (fd == tfd) { handle_timer(tfd); } else if (fd == STDIN_FILENO) { char buf[256]; ssize_t r = read(STDIN_FILENO, buf, sizeof(buf) - 1); if (r <= 0) { printf("stdin closed, exit\n"); goto done; } buf[r] = '\0'; printf("[stdin] %s", buf); } } } done: close(tfd); close(epfd); return 0; }

4.3 关键步骤拆解

第一步,创建 timerfd。用CLOCK_MONOTONIC保证不受系统时间调整影响,加TFD_NONBLOCK是为了后面万一切 ET 模式不用改,加TFD_CLOEXEC是防御性编程。

第二步,设置定时参数。这里initial_ms=1000表示 1 秒后首次触发,interval_ms=500表示之后每 500ms 一次。注意it_value和it_interval都要填,只填一个的话行为不符合预期——只填it_value就是 one-shot,只填it_interval则首次触发时间不确定。

第三步,注册到 epoll。ev.data.fd存 fd 本身,回调时用它区分事件来源。生产代码里更常见的做法是ev.data.ptr指向一个结构体,里面带 fd、类型、回调函数指针,这样扩展性更好。

第四步,事件循环。epoll_wait的 timeout 传 -1 表示无限等待,因为定时逻辑已经交给timerfd了,不需要靠超时参数兜底。EINTR要单独处理,信号打断时继续循环,不要当成错误退出。

第五步,读取到期次数。这一步必须做,否则 LT 模式下epoll_wait会一直返回这个 fd 可读,陷入忙循环。这是新手最常犯的错误之一。

4.4 运行效果与验证

编译运行后,你会看到每秒开始每 500ms 打印一次[timer] fired 1 time(s)。如果你在终端输入一行文字回车,会看到[stdin]的输出,说明两类事件在同一个循环里被正确处理。

想验证"合并到期"的行为,可以在handle_timer里加一句sleep(2),然后观察输出。你会发现某次打印的到期次数变成了 4 左右,这就是前面说的"卡住期间累积的到期次数"。这个特性在做限流、统计类任务时非常有用。

5. 常见问题与排查技巧实录

5.1 高频问题速查表

现象可能原因排查方向
epoll_wait一直返回 timerfd 可读没有read()或读的字节数不对检查是否读满 8 字节
timerfd_settime返回 EINVALtv_nsec超出范围检查纳秒字段是否 < 1e9
定时器完全不触发it_value设成了 00 表示 disarm,要设非零
首次触发时间不对混淆了it_value和it_interval首次看it_value,周期看it_interval
多线程下事件丢失多个线程同时epoll_wait同一个 epfd用 EPOLLONESHOT 或单线程收事件
系统时间调整后定时错乱用了CLOCK_REALTIME换成CLOCK_MONOTONIC
fd 泄漏到子进程没加TFD_CLOEXEC创建时补上该 flag

5.2 几个文档里不会写的坑

坑一:read()缓冲区大小。我一开始用int接收到期次数,结果read()返回EINVAL。原因是内核要求缓冲区至少 8 字节,int只有 4 字节。必须用uint64_t。这个错误信息很隐晦,perror只打印 "Invalid argument",不看源码根本猜不到。

坑二:LT 模式下忘记 read 导致 CPU 打满。有一次线上服务 CPU 突然飙到 100%,查了半天发现是某个定时器回调里抛异常提前返回了,没走到read()。LT 模式下 fd 一直可读,epoll_wait立刻返回,形成忙循环。解决办法是在回调最外层用 RAII 或者goto保证read()一定被执行,或者干脆切 ET 模式。

坑三:timerfd_settime的old_value参数。这个参数可以传 NULL,但如果你想实现"暂停后恢复"的功能,就需要先读出来旧值。注意读出来的it_value是剩余时间,不是原始设置值,恢复时要重新计算。

坑四:精度不是无限的。虽然接口是纳秒级,但实际精度受内核HZ配置和调度延迟影响。普通服务器上做到 1ms 精度没问题,想做到 10 微秒级就得考虑实时内核或者忙等待方案了。别被"纳秒"两个字误导。

坑五:fork 之后的行为。timerfd在fork后子进程会继承,但父子进程共享同一个定时器状态。如果子进程也去read(),会跟父进程抢到期事件。正确做法是 fork 后子进程立即close()掉不需要的 timerfd,或者干脆在 fork 前就规划好 fd 归属。

5.3 一个实用的封装思路

实际项目里不会只有一个定时器。我的做法是封装一个Timer类,内部持有timerfd,注册到全局epoll,回调时调用用户传入的std::function。多个定时器就是多个timerfd,各自独立,互不干扰。相比时间轮方案,这种"一定时器一 fd"的做法在定时器数量不多(几百个以内)时完全够用,而且逻辑简单不容易出错。数量上千之后再考虑时间轮优化。

注意:每个timerfd都占用一个 fd,系统默认 fd 上限是 1024(ulimit -n可查)。如果你的服务要开几千个定时器,要么调大上限,要么改用时间轮。这是选型时必须提前算清楚的账。

6. 性能特征与适用边界

6.1 开销到底有多大

timerfd的创建和设置都是系统调用,单次开销在微秒级。事件触发时,内核把 fd 标记为可读并唤醒epoll_wait,这个路径和普通 IO 事件完全一样,没有额外负担。实测下来,单进程管理几百个timerfd,每秒触发几千次,CPU 占用可以忽略不计。

真正需要注意的是回调执行时间。如果定时器回调里做了耗时操作,会阻塞整个事件循环,导致其他定时器和 IO 事件延迟。所以回调里只做轻量逻辑,重活丢到线程池或者用eventfd唤醒工作线程。

6.2 什么场景不适合用

  • 超高频定时(微秒级):系统调用开销占比过高,考虑忙等待或者专门的实时方案。
  • 海量定时器(上万级):fd 数量成为瓶颈,时间轮更合适。
  • 跨平台需求:非 Linux 平台没有timerfd,需要抽象层或者换方案。
  • 需要挂钟时间语义:比如"每天固定时刻执行",用CLOCK_REALTIME配合TFD_TIMER_ABSTIME可以,但要处理系统时间跳变,逻辑比想象中复杂。

6.3 和其他机制的配合

timerfd经常和eventfd、signalfd一起出现,构成完整的事件循环基础设施。eventfd用来做线程间唤醒,signalfd把信号也变成 fd,三者加上 socket,全部由同一个epoll管理。这套组合是很多高性能服务的标准骨架,理解了timerfd,另外两个也就触类旁通了。

我在实际项目里踩过几次坑之后,现在的习惯是:任何需要定时的逻辑,先问自己"这个定时器会不会被卡住、卡住后要不要补触发"。如果答案是"要补",那timerfd的到期计数就是刚需;如果"无所谓",那用epoll_wait超时也能凑合。想清楚这一点,选型就不会纠结了。

相关新闻

YOLO26接入LaSEA注意力模块:原理复现与红外小目标检测实战

YOLO26接入LaSEA注意力模块:原理复现与红外小目标检测实战

YOLO系列的改进我做了不止一两个&#xff0c;但这次这个LaSEA模块值得单独拎出来详细讲讲。TGRS 2026上那篇关于潜在感知语义提取聚合的工作&#xff0c;核心思想其实很朴素&#xff1a;与其在特征图上反复堆叠注意力权重&#xff0c;不如先把深层语义信息显式提取出来&#xf…

2026/10/19 17:17:45 阅读更多 →
算法竞赛STL入门:vector/set/map等容器核心用法与避坑指南

算法竞赛STL入门:vector/set/map等容器核心用法与避坑指南

如果你刚开始刷算法竞赛题&#xff0c;大概率经历过这种绝望&#xff1a;题目思路想明白了&#xff0c;代码却写得又长又容易崩&#xff0c;光是一个排序就要手写二三十行&#xff0c;调半天还出边界问题。这其实不是你菜&#xff0c;而是你还没学会用 STL。《算法竞赛入门经典…

2026/10/19 17:17:44 阅读更多 →
如何让 Code Review 不再流于形式?Open-Code-Review 完整落地指南

如何让 Code Review 不再流于形式?Open-Code-Review 完整落地指南

1. 为什么我把 code review 从"可做可不做"变成"必做"先说个真实的翻车现场。前两年我们团队有个服务一直跑得好好的&#xff0c;直到某次大促前一天晚上&#xff0c;流量一上来&#xff0c;接口直接雪崩。查了半天&#xff0c;根因是一个同事提交的代码里…

2026/10/19 17:17:44 阅读更多 →

最新新闻

Product Hunt热榜复盘:从票数与评论区看产品冲榜策略

Product Hunt热榜复盘:从票数与评论区看产品冲榜策略

我每天早上都会打开 Product Hunt 的热榜页面&#xff0c;这已经是雷打不动的习惯。2026-03-31 的这份榜单&#xff0c;我点开之前其实没抱太大期待——毕竟“每日热榜”四个字听起来就像流水账。但真正逐条把当天上榜的产品翻完、把评论区看完、把背后几位创始人的发布策略捋清…

2026/10/19 18:05:50 阅读更多 →
C#类成员详解:字段、属性、构造函数及面试要点

C#类成员详解:字段、属性、构造函数及面试要点

1. 为什么"简述类成员"值得你认真准备 我以前参与技术面试时&#xff0c;经常用"简述类的成员"这道题做开场。原因很简单&#xff1a;它听起来基础得不像话&#xff0c;但实际考察的层次非常深。一个候选人如果连这道题都答得有结构、有主次&#xff0c;那…

2026/10/19 18:05:50 阅读更多 →
达梦8 DSC共享存储集群在VMware虚拟化环境中的部署实践与踩坑指南

达梦8 DSC共享存储集群在VMware虚拟化环境中的部署实践与踩坑指南

1. 项目拆解&#xff1a;达梦8 DSC在虚拟化环境中的定位和难点1.1 达梦8 DSC到底是什么达梦8的DSC全称是Data Shared Cluster&#xff0c;也就是共享存储集群方案。它的逻辑跟很多人熟悉的Oracle RAC类似&#xff1a;两个或多个实例节点&#xff0c;通过共享存储访问同一份数据…

2026/10/19 18:05:50 阅读更多 →
Python全栈从0到上岗:项目实战打通全链路

Python全栈从0到上岗:项目实战打通全链路

先泼一盆冷水&#xff1a;全网铺天盖地的“Python全栈教程”“30天从入门到精通”“学完就能月薪过万”……至少有一半是坑。不是蹭这个项目标题的热度&#xff0c;是我见过太多零基础学习者&#xff0c;对着几百集的视频刷了三个月&#xff0c;笔记记了好几本&#xff0c;但打…

2026/10/19 18:05:50 阅读更多 →
Java连接MySQL全流程详解:JDBC原理、连接池、事务与性能优化

Java连接MySQL全流程详解:JDBC原理、连接池、事务与性能优化

只要你的 Java 项目叫“业务系统”&#xff0c;就逃不开 MySQL。这句话我说了快十年&#xff0c;带过的新人没有一个能反驳。很多人第一次连数据库&#xff0c;都是在搜索引擎里复制一段三行代码&#xff0c;跑通了就丢到生产环境&#xff0c;然后被时区报错、中文乱码、连接超…

2026/10/19 18:05:50 阅读更多 →
从零实现轻量级图表编辑器:Canvas渲染与数据驱动架构解析

从零实现轻量级图表编辑器:Canvas渲染与数据驱动架构解析

图表设计工具这类项目&#xff0c;名字叫 "diagram-design" 的其实蛮多的&#xff0c;但真正能让人愿意截图发出来的产品很少。我这次想聊的&#xff0c;是我自己从零搭起来的一个轻量级图表设计方案——一个跑在浏览器里的流程图、架构图编辑器。核心思路很简单&…

2026/10/19 18:04:45 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介&#xff1a;本资源为电源技术方向的学术研究文档&#xff0c;聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略&#xff0c;面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址&#xff1a; https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集&#xff0c;共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →