CPU缓存原理解析:从缓存行到伪共享的性能优化实践
有段时间我被一段看结果完全正确、但运行时间出奇慢的统计程序折腾了整整一下午。最后定位到的原因不是算法复杂度而是 CPU 缓存的基本概念对应的底层机制出了问题——两个线程在持续修改两个恰好落在同一个缓存行里的变量。如果你没接触过缓存的基本概念很容易把这类问题往业务逻辑、数据库连接、网络 IO 等方向硬查查到最后才发现是硬件层在拖后腿。CPU 缓存听起来像计算机组成原理课本里的内容但它离我们写代码并没有那么远。只要是追求性能的人无论是后端开发、客户端开发还是做数据计算迟早都会和它碰面。这篇文章我打算把缓存的基本概念完整过一遍CPU 为什么需要缓存缓存怎么组织数据读写时发生了什么多核下为什么会有奇怪的问题以及作为开发者要怎么观察和规避缓存带来的坑。里面没有太多需要死记硬背的东西更多是一套能直接解释日常性能现象的思考框架。1. CPU 缓存到底解决了什么问题1.1 一次内存访问要等多少个 CPU 周期当代 CPU 执行指令的速度快得有点反直觉。现在一颗普通的桌面处理器主频通常能到 3GHz 上下也就是说硬件上每秒钟能发起几十亿次基本运算周期单个周期的时间大约只有 0.3 纳秒左右。内存读一次数据需要多久呢主流内存在典型访问模式下的延迟大体在 80 到 120 纳秒这个量级。拿最简单的算术来看一次内存访问少则等两三百个周期多则四五百个周期CPU 干等着数据回来。这个差距不是几个百分比而是两个数量级。为了让抽象数字更好理解我习惯把 CPU 比作在书桌上写作业的人把内存比作房间里的书架。CPU 每次要从内存取一个数就像你从座位上站起来走到书架找到需要的资料再回到座位继续写。偶尔站起来拿一次还好但如果每写几个字就要跑一趟效率就全耗在路上了。缓存在这里就相当于桌面上的资料夹和随手能碰到的工具把真正高频使用的数据放在离人最近的地方。这也是“CPU 基础知识”里最值得先理解的一环。这里自然会产生一个疑问既然缓存能解决速度问题为什么不把整块内存全部换成和缓存一样快的存储器答案在于成本和功耗。缓存通常用静态随机存储器内部单元的晶体管数量远多于主存使用的动态随机存储器同样容量下成本高一个数量级不止发热也更明显。如果整个内存都用缓存那样的结构售价和散热都会变成灾难。所以硬件设计者选择了折中方案把存储体系拆成从快到慢、从贵到便宜、从容量小到容量大的多个层级。存储层级典型延迟容量量级作用范围寄存器1 个周期几十到几百字节每个核心内部L1 缓存4 个周期左右几十 KB每个核心私有L2 缓存10 到 20 个周期几百 KB 到几 MB每个核心私有或两核共用L3 缓存30 到 50 个周期几 MB 到几十 MB多核共享内存200 到 300 个周期起几 GB 到上百 GB全系统共享表里的具体数字会随架构和型号变化但数量级关系长期稳定。这也是为什么“看缓存表”经常出现在性能分析的第一步知道数据在哪一层基本就知道一次访问大概要付出什么代价。1.2 局部性原理缓存能省时间的根本原因不过多级存储只是硬件基础缓存能不能真正起作用依赖的是几乎所有程序都具备的局部性原理。局部性包括时间局部性和空间局部性两方面。时间局部性不难理解。一段循环代码里的变量和指令会在短时间内反复被引用。比如循环计数器 i每一轮循环都要读它、修改它、比较它如果这个变量第一次访问时就留在缓存里后续每次使用都能直接命中。再想想那些频繁调用的函数函数所在的指令区域也会被反复读取这些都属于时间局部性的体现。空间局部性则指程序倾向于访问彼此相邻地址的数据。最典型的例子是遍历数组时从 array[0] 一路读到 array[n]内存地址连续递增相邻元素在物理上挨在一起。CPU 读到第一个元素时会把附近一片数据一起搬进缓存后续读后面几个元素时就不用再去内存了。把这两条局部性原理记住后面很多优化思路都能顺理成章。比如为什么推荐遍历二维数组时按行优先而不是按列优先本质就是你得访问满足空间局部性让缓存一次搬来的数据尽量被用掉。如果你的代码总是东跳一下西跳一下内存地址毫无连续性缓存命中率会非常难看性能自然大幅下滑。1.3 多级缓存是怎么分工的在多级缓存里L1 通常还会分为 L1i指令缓存和 L1d数据缓存分别存放指令和数据避免取指和访存在同一个前端里互相争抢。L1 最靠近核心延迟最低但容量极小通常只有几十 KB。L2 被设计得比 L1 更大能吸纳那些从 L1 被淘汰出去、但还没远到必须直接回到内存的数据。L3 则往往是整个 CPU 多个核心共享的部分容量最大远大于单个核心的私有缓存。理解“私有的一二级缓存和共享的三级缓存”这件事很重要它是多核缓存一致性问题的源头。你可以把 L1/L2 想成每个核心自己书桌上的草稿纸各自记录着从共享大书架上摘抄的内容L3 像一个多人共用的中转柜大家都可以往里面放东西但整理不好就容易造成“我以为你改过了其实你那本还是旧版本”的尴尬。2. 缓存行、组相联和地址拆分缓存的核心结构2.1 缓存行是数据存取的最小单位缓存读写的最小单位是什么不是字节而是“缓存行”。最常见的行大小是 64 字节部分架构也使用 32 或 128 字节。你写一行 C 代码int a arr[0];实际上 CPU 很可能把 arr[0] 所在的那一整块 64 字节都搬进缓存然后在这个基础上把 arr[0] 取出来交给你。为什么要把粒度设计得这么大核心出发点就是空间局部性。数组是连续存放的一次拿走一整行能覆盖接下来可能被访问的好几个相邻元素减少后续访问内存的次数。从硬件成本看每个缓存行还得配一个标记位和若干管理信息如果行做得太小同样容量下需要维护的行数就越多标记开销和淘汰成本都会上升如果行做得太大又可能一次搬回太多用不到的数据导致缓存有效利用率下降、内存带宽被浪费。64 字节是多年设计平衡后相当常见的折中点。2.2 三种映射方式位置越自由查找越麻烦内存比缓存大得多某个内存块进入缓存后到底放在哪个位置不同的放置规则形成缓存的不同映射方式。第一是直接映射。把内存块按编号对应到缓存中的唯一位置。比如某个缓存中有 16 个位置内存块 0、16、32……都只能进同一个位置。好处是查找简单硬件按位置算好后直接看这是哪个内存块就行开销小坏处也明显多个常用地址会反复抢占同一个位置导致刚加载的数据很快被挤出去命中率起伏很厉害。第二是全相联。任何内存块可以放入缓存中的任意位置。从空间利用角度这是最理想的但硬件必须在一个缓存行到达时和整个缓存里所有行逐一比对标记才能判断是否命中并行比较器成本非常高所以通常只用在容量很小的结构里例如 TLB 这一类场景。第三是组相联也是现代 CPU 缓存的主流方案。它先把缓存分成许多组组内再分出若干路在地址中选出一段“组编号”作为索引先定位到某一组再允许新数据放进该组里任意一路。常见路数有 4 路、8 路、16 路。可以说它是直接映射和全相联的折中既控制住了比较范围也不会让多个内存地址因为只能挤一个位置而疯狂内耗。映射方式能放的位置查找复杂度硬件成本典型问题直接映射只能放在唯一槽位最低低冲突未命中容易偏高组相联放在指定组内的任意路组内并行比较中等绝大多数处理器使用全相联缓存中任意位置全部行比较高适合小容量结构2.3 一条地址如何被拆成 Tag、Index 和 Offset要理解组相联怎么工作还得看 CPU 发出的地址在硬件层面被拆成了三段Tag标记、Index索引、Offset块内偏移。Offset 用来在缓存行内部找具体字节。如果行大小是 64 字节Offset 就需要 6 bit因为 2 的 6 次方等于 64。Index 用来定位到具体某个组。如果缓存有 64 组Index 也需要 6 bit。剩下那些高位就是 Tag用来确认这一行的真实身份是不是刚才要找的那个内存地址。这里补一个简单计算。某缓存容量是 32KB8 路组相联行大小 64 字节。每行 64 字节那么 32KB 一共能容纳 32768 除以 64 等于 512 个缓存行。8 路组相联表示每组里有 8 行因此组数是 512 除以 8 等于 64 组。反过来也成立缓存容量等于组数乘以路数再乘以行大小64 组乘以 8 路乘以 64 字节正好是 32KB。这类计算在分析性能问题时很实用。它能帮你理解为什么同一个程序在“恰好撞上缓存结构”时性能会突然变化也能让你明白为什么某些内存布局需要做填充或错位。2.4 一次缓存查找的完整流程把前面的概念串起来CPU 访问一个数据时的流程大致如下拿到完整地址后先从地址中切出 Index。用 Index 定位到对应的组。在组内的多路缓存行里并行比较 Tag同时检查有效位。如果找到 Tag 匹配且有效的行再根据 Offset 从行中取出对应字节这就是缓存命中。如果没找到就是缓存未命中CPU 需要向下一级缓存或主存请求数据并把拿到的整行数据放进缓存之后可能触发组内淘汰。这个过程在硬件层面高度并行、流水线化执行单个查找动作非常快。但对写代码的人来说只需要记住一个结论命中与未命中的代价相差一到两个数量级很多性能优化本质上都是在试图减少未命中而不是每次去改写更“快”的代码。3. 写缓存、替换策略和多核一致性问题3.1 写直达和写回修改后的数据什么时候落地读缓存时如果没命中把整块数据从内存搬进缓存然后继续读即可逻辑相对简单。写缓存则要复杂得多核心问题是修改后的数据什么时候真正落到内存里如果每次写都同步写内存缓存的意义就少了一大半如果不同步写内存里保存的又可能是旧值。缓存阵营里大致有两种写策略。写直达也叫 Write Through每当 CPU 修改缓存行同时也把数据写到内存。优点是容易理解内存数据随时最新做一致性也简单缺点是每一次写操作都要承受内存延迟写多的时候总线压力很大性能并不好。写回也叫 Write Back是多数高性能系统的选择。CPU 改数据时只修改缓存行并在这一行打上“脏标记”。当这个缓存行因为新数据进入而被逐出时硬件先检查脏标记如果是脏的就把整行写回内存再腾出位置给新数据如果不脏说明内容和内存一致可以直接覆盖。好处是中间多次修改整体并成一次真正的内存写写放大问题小得多。写策略修改缓存时写内存时机优点缺点写直达同时写缓存和内存每次写操作都发生内存始终新、实现简单写性能差、总线压力大写回只改缓存并标脏缓存行逐出时写回写性能好、写流量少需要维护脏标记和一致性3.2 缓存替换策略满的时候淘汰谁缓存容量有限新数据进来时如果组内已经满了就必须淘汰一个旧缓存行。淘汰谁会直接影响命中率。最理想的是淘汰“未来最久不会被访问”的行但硬件没法预测未来只能用历史推测未来。最经典的是 LRU最近最少使用。如果一个缓存行最近被访问过就认为它在接下来更可能再被用到所以优先淘汰组内最久没被访问过的那一行。LRU 在大量场景下效果很好但硬件层面记录访问时序的代价不小。因此很多处理器使用伪 LRU用少量 bit 维护一个近似最近访问顺序成本和效果更平衡。除此之外还有 FIFO 和随机替换。FIFO 按进入顺序淘汰逻辑简单但完全不关心最近是否有访问随机替换实现简单在部分分支复杂的场景下表现也不差。对普通开发者来说不必一开始就纠结每种算法关键是理解一个事实缓存并不保证你认为重要的数据一定留在里面如果热点数据总量超过缓存容量未命中必然反复发生。3.3 MESI 协议多核缓存为什么不一致缓存写到多核场景后麻烦立刻出现。两个核心各自读了一个变量并缓存在各自的 L1之后核心 A 修改了变量核心 B 不知道情况还继续用自己的旧副本这就叫缓存不一致。硬件必须有一套缓存一致性协议来规范各个缓存行的状态以及相互通信。最常见的教学示例是 MESI 协议。MESI 定义了四种状态Modified已修改、Exclusive独占、Shared共享、Invalid无效。我用一个简化的状态故事来说明。核心 A 第一次读取某个地址如果发现其他核心都没在读同一行该行在 A 中通常会标记为 E意思是没有其他副本且内容还和内存一致。这时核心 A 要写这个数据因为自己是独占的修改动作不需要通知别人直接改行变成 M。之后核心 B 也来读同一地址A 为了进入共享状态会先把行写回内存并保留副本状态从 M 变成 SB 也拿到一份标记为 S 的副本。现在如果 A 又要写情况就不同了因为存在多个副本A 需要向其他核心发送失效消息让 B 把自己那行标成 I。B 下次再读时发现自己的副本无效只能从 A 或内存里重新拿最新值。时序稍微复杂但核心不难理解多个核心共享同一缓存行时谁要写谁就得先“独占”让别人手里的副本失效。这也是为什么多线程写多读少的数据性能容易受严重影响。缓存一致性并不是靠上层语法来实现的它发生在硬件层即使你的代码没有显式加锁只要两个核心竞争同一缓存行协同成本依然存在。3.4 伪共享两个变量根本没有共享却互相拖累和缓存一致性紧密相关的一个经典坑是伪共享。它指两个线程修改的变量在逻辑上毫无关系物理地址却恰好落在同一个缓存行里。对程序来说两个变量属于不同数据项线程之间“看起来”没有共享状态但硬件缓存行粒度却让它们真实地互相挤占。假设同一缓存行里有 x 和 y线程 1 只改 x线程 2 只改 y。线程 1 每次修改都会触发缓存行失效线程 2 手里的副本随即作废线程 2 再改 y 时又要重新同步整行。每轮修改都在两层缓存之间来回搬即便两个核心根本不去碰对方的变量性能也会被拖得很惨。缓解伪共享的思路很直观让两个热变量的物理地址拉开距离不再落进同一个缓存行。一种做法是在变量之间填充足够多的字节另一种更彻底的方式是让热点数据各自对齐到缓存行的起始位置。在真实的并发计数器示例里仅仅做这个改动性能经常能提升好几倍。4. 观察缓存行为、定位常见的坑4.1 查看当前 CPU 的缓存参数经常有人问怎么查看机器上的缓存参数。在 Linux 系统里最方便的是 lscpulscpu | grep -i cache输出大致长这样L1d cache: 32K L1i cache: 32K L2 cache: 512K L3 cache: 16M如果想确认缓存行大小可以直接读 sysfs 下的接口cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_sizeindex0、index1、index2 通常对应不同级别的缓存。这套信息对验证伪共享、确认缓存行大小、设计结构体对齐都非常有用。4.2 用 perf 看 cache miss光看参数还不够定位程序性能问题最重要的一步是测量。Linux 下的 perf stat 可以很方便地拿到缓存相关计数器perf stat -e cache-references,cache-misses,L1-dcache-loads,L1-dcache-load-misses ./test_program跑完直接看计数器之间的对比。L1-dcache-load-misses 代表 L1 数据缓存读未命中次数cache-misses 通常对应最后一级缓存的未命中次数。真正让性能出现明显下跌的通常是最后一级缓存的 miss因为数据需要到内存去取几百个周期的等待很难用其他方式藏住。提醒一句不要只看 miss 的绝对次数要把它和对应操作总数结合来看。比如一个程序的 L1 未命中率只有 2%但访问基数很大绝对次数也会很夸张反过来对大数组连续读miss 次数很高但由于空间局部性强总体耗时未必不能接受。4.3 亲手验证空间局部性按行访问和按列访问用一段小代码演示空间局部性的差别是很直观的学习方式。比如一个二维数组#define SIZE 2048 static int matrix[SIZE][SIZE]; long sum_row(void) { long total 0; for (int i 0; i SIZE; i) for (int j 0; j SIZE; j) total matrix[i][j]; return total; } long sum_col(void) { long total 0; for (int i 0; i SIZE; i) for (int j 0; j SIZE; j) total matrix[j][i]; return total; }sum_row 顺着内存连续地址走每次缓存行被搬进来后续相邻元素都能直接用命中率很高。sum_col 每次都跳到下一行的另一个列位置缓存行里大部分字节还没用就被丢弃随即频繁 miss。在我的测试环境里这个差距通常达到 4 到 8 倍。当然具体数字与矩阵大小、编译器优化、CPU 缓存容量都有关建议当作概念验证来跑而不是直接背结论。注意如果你用较高优化等级编译这段代码编译器可能对循环做变换导致差距变小。想验证缓存效果最好先关闭相关优化或给累加结果加一个让编译器无法随意改写的约束。4.4 常见缓存性能问题速查表现象可能的缓存问题怎么检查常用解法同样逻辑数据量只多一点点耗时暴涨数据超出缓存容量容量 miss 大量增加对比不同规模下的 miss 率分块处理让热点子集留在缓存中单线程很快多线程反而很慢多个核心争抢同一缓存行伪共享检查线程访问的变量地址是否落在同一行填充、对齐或把数据分散到不同缓存行数组遍历特别慢算法复杂度却不低访问顺序不满足空间局部性对比连续访问和跳跃访问的耗时按行优先、调整数据结构布局某个热点变量被反复改写性能抖动缓存行频繁失效和回写看缓存 miss 和总线竞争适当使用线程本地副本减少共享写改一行代码位置性能差一倍冲突 miss 加剧做内存布局测试调整字段顺序、补充填充字节4.5 写代码时可以实践的几个方向最后聊几句我在实际优化中的体会。第一个原则是优化尽量建立在测量之上。缓存的 miss 率、特定循环的耗时都要用工具量化不要凭“我觉得这里会 miss”去改代码。第二个原则是优先调整数据布局而不是一上来就推翻算法。很多性能问题的本质是访问模式不好把一个被反复读取的字段挪到结构体靠前的位置或者把一块热点区域单独组织出来效果往往比抠几行小细节还明显。第三跨线程共享的数据要格外谨慎。什么时候需要把两个变量分散到不同缓存行当两个线程各自频繁更新不同变量时同一缓存行会制造隐性的互相驱逐和失效。用 64 字节对齐或者填充把它们隔开经常是性价比很高的改动。我在开头提到的那个统计程序最后就是这样修好的两个计数器在内存里靠得太近几行 padding 一加吞吐立刻恢复正常。最后再分享一个小技巧当你怀疑性能问题和缓存有关时试着把数组访问顺序反过来跑一遍或者把两个热点变量加上填充重新测一次。如果结果出现数量级差异那基本就是缓存命中率在起作用。这种改动比任何例行优化手段都更能说明问题也很适合当作新人理解 CPU 缓存的第一课。

相关新闻

Linux uname命令全解析:从内核信息到架构判断的实战指南

Linux uname命令全解析:从内核信息到架构判断的实战指南

拿到一台新服务器或者接手一套陌生环境时,我习惯先跑一条uname -a。原因很简单:这条命令不会因为缺少某个软件包、没有图形界面、连不上外网而罢工,只要内核起来了,它就能给你吐出一串关键信息。很多朋友喜欢一上来就cat /etc/os-…

2026/10/13 6:58:01 阅读更多 →
LeetCode 26双指针解法:有序数组去重核心是覆盖而非删除

LeetCode 26双指针解法:有序数组去重核心是覆盖而非删除

新手刷题绕不开的一道题就是LeetCode 26,删除有序数组中的重复项。这道题在“新手友好题解与思路解析”这个标签下经常出现,但真正动手做的时候,很多人反而栽在了一个看似简单的要求上:原地修改。我第一次刷这道题也翻了车&#x…

2026/10/13 6:58:08 阅读更多 →
广东省SHP数据处理指南:行政区划与路网分析实战

广东省SHP数据处理指南:行政区划与路网分析实战

简介:一份基于Shapefile(SHP)格式的广东省地理空间数据包,面向GIS开发、城市规划与交通研究人群,提供省、市、县三级行政区划边界,以及道路网、铁路网两类关键交通要素。借助这些矢量图层,可直接…

2026/10/13 6:57:18 阅读更多 →

最新新闻

迷你SQL 2000轻量数据库:DLL清单、部署与排错指南

迷你SQL 2000轻量数据库:DLL清单、部署与排错指南

简介:迷你SQL 2000是一款面向Windows平台的轻量级数据库管理系统,适配WINXP、WIN7及WIN10的32位与64位环境,适合个人用户与小型企业解决低资源占用下的数据存储与管理需求。它可视为SQL Server 2000的精简版本,保留数据库引擎与基…

2026/10/13 13:01:12 阅读更多 →
技术博客标题缺失:t3code无法解析的合规性说明

技术博客标题缺失:t3code无法解析的合规性说明

我无法根据“t3code”这一标题生成符合要求的博文内容。原因如下:标题信息严重不足: “t3code”本身不具备明确语义,既非广为人知的开源项目(如未在GitHub、NPM、官方文档或主流技术社区中形成共识性指代),…

2026/10/13 13:01:12 阅读更多 →
揭秘市面上那些热门的SEO优化服务机构!

揭秘市面上那些热门的SEO优化服务机构!

痛点深度剖析我们团队在实践中发现,当前SEO优化行业存在诸多难题。众多客户反馈,做了半年的SEO优化,关键词排名毫无提升,对SEO效果产生质疑,技术白皮书显示,多数传统SEO见效周期长,流量获取成本…

2026/10/13 13:01:12 阅读更多 →
t3code 跨平台工具链实战:Electron 桌面端与 CLI 安装配置全指南

t3code 跨平台工具链实战:Electron 桌面端与 CLI 安装配置全指南

1. 从 t3code 这个关键词说起:它到底指什么第一次看到 "t3code" 这个词,很多人会一头雾水。它不像 "vscode" 那样有明确的官方定义,也不像某个知名框架那样有完整的文档站。从热词组合来看,t3code 更像是一个…

2026/10/13 13:01:12 阅读更多 →
感知机入门:从零实现到多层感知机突破异或问题

感知机入门:从零实现到多层感知机突破异或问题

感知机(Perceptron)是神经网络最初的模样,也是很多人入门深度学习时绕不过去的第一个模型。说它门槛低,是因为你只要会加权求和,再写一个 if 判断,就能把一个感知机跑起来;说它后劲大&#xff0…

2026/10/13 13:01:12 阅读更多 →
Unity水下波光Shader:动态折射与材质自适应光照实现

Unity水下波光Shader:动态折射与材质自适应光照实现

1. 这个效果到底在解决什么问题:水面光影的“动态欺骗”本质很多人看到“Unity Shader实现水中波光照射动物身上的效果”这个标题,第一反应是:“不就是加个高光贴图或者用个Blinn-Phong算一下反射吗?”——这恰恰是踩进第一个认知…

2026/10/13 13:00:12 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 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/12 21:05:09 阅读更多 →
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/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练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/12 18:11:17 阅读更多 →