Claude能写出更快的代码,但基准测试才是裁判
发布时间:2026/9/15 20:13:22 锦皓数字建站

1. 先说结论Claude 生成的是候选方案不是实验结果我最近让 Claude 帮我优化一段 C 语言的文件读写代码。它给了一个看起来很专业的方案把逐字符的fgetc改成fread加固定缓冲再把循环里的strlen提到循环外面顺便标注了减少系统调用次数和避免重复扫描两个理由。专业、清晰、有层次当时我差点直接把这段代码写进提交信息。幸好我多跑了一次基准测试。结果很有意思在小文件场景下优化后的版本确实快了不少但换成一个已经被操作系统缓存过的 1GB 文件再把编译器优化级别从-O0换成-O2差距大幅缩小而当我改用一个网络挂载目录里的文件时两个版本都卡在 I/O 上优化直接失去了意义。那一刻我意识到一个经常被忽略的事实Claude 能写出更快的代码但它不能证明代码真的更快。1.1 大模型写代码的运行逻辑要理解这件事得先看懂 Claude 这类模型是怎么给出代码的。它的本质是一个根据前文预测后续 token 的概率模型。训练数据里有无数的开源代码、技术博客、Stack Overflow 回答所以当你问如何让 C 语言文件读写更快时它大概率会复现资料里出现频率最高的几种做法批量读取、减少系统调用、增大缓冲区、避免重复计算。这些做法本身没有问题问题在于模型并不真正运行你机器上的代码也不认识你手上的数据规模和硬件环境。它不知道你的文件是 1KB 还是 100GB不知道你是机械硬盘还是 NVMe SSD不知道数据是否在 page cache 里也不知道你的编译器会做哪些优化。它给的更快是从语料分布里统计出来的看起来更快不是在你环境里实测出来的真的更快。1.2 更快这三个字在 LLM 里没有可验证的含义如果你让 Claude 解释某段代码是做什么的它能讲得很好。但如果你让它判断A 和 B 哪个更快它其实是在做一种隐式的概率推断在它见过的文本里A 类方案通常比 B 类方案快或者某篇热门文章里明确写了 A 更快。这不是坏话所有专家给建议时也是在调用经验差别在于人类专家会说这个取决于你的场景你需要跑 benchmark而模型很容易用笃定的口吻说出一个未经实验的结论。所以在性能优化这件事上Claude 更适合扮演候选方案生成器而不是性能裁判。裁判必须用计时器和数据说话。1.3 谁需要关心这件事只要你让人工智能工具参与代码性能优化这件事就和你有关。不管你用的是 Claude、Claude Code 这类终端编程助手还是其它 AI 编程插件日常写 LeetCode 题、处理批量数据、优化 C/C 模块、给 Python 量化策略提速、甚至写一段 Windows 批处理脚本去调游戏性能最终落到生产环境前都必须有人为真的更快这件事兜底。这个兜底动作就是基准测试。2. 把更快拆成可测的东西先定位瓶颈再谈优化Claude 给出优化建议时我见过最常见的错误是用户直接说帮我优化这段代码然后不管三七二十一把模型输出的每个改动都合进去。这样做风险很高因为你可能优化了一个根本不是瓶颈的环节甚至破坏原有的正确性。2.1 至少分清三种瓶颈性能瓶颈大致可以分成三类这三类的优化方向和对 Claude 提问的方式完全不同。CPU 密集型程序大部分时间花在计算上比如快速排序、数值计算、图像处理算法。优化方向是减少指令数、改善分支预测、利用 SIMD、选更好的数据结构。I/O 密集型程序在等磁盘、网络、数据库响应。优化方向是减少读写次数、增大缓冲区、改异步 I/O、上缓存。内存密集型程序在频繁分配和释放内存或者因为缓存命中率低而变慢。优化方向是减少分配次数、改善内存复用、调整数据结构布局。如果你的代码明明卡在数据库查询上Claude 却给你优化了一段加密算法那这段优化大概率没有任何实际收益。所以先别急着让 Claude 动手先用性能工具或者你自己的经验定位问题在哪。2.2 优化前先记录基线数据我强烈建议你把优化前的性能数字当成代码的一部分保存下来。没有基线后面的对比就是空中楼阁。最简单的做法就是先用系统自带工具跑一遍。Linux/macOS 下可以用time your_program input.txt /dev/nullmacOS 上想看更详细的峰值内存用/usr/bin/time -l your_programLinux 上想看 CPU 利用率、缓存命中率、上下文切换这些更细的指标可以先装perf再用perf stat your_programWindows 下 PowerShell 里可以用Measure-Command { .\your_program.exe }这一步的目的不是得到多精确的数字而是先给优化前后找一个共同参照系。记录的时候还要写上测试环境CPU 型号、操作系统版本、编译器版本、编译选项、输入数据大小。没有这些上下文数字就是孤零零的。2.3 计时工具怎么选很多人喜欢用代码里的clock()或time.time()计时但这里有个坑这些接口测的是程序内部视角的时间不包含进程启动加载、页表建立、I/O 等待等开销。对于优化某个核心函数来说这样测没问题但对于整个程序是否变快这个问题最好用外部计时工具。我目前最常用的是hyperfine它非常适合对比同一个程序的多个版本hyperfine --warmup 3 --runs 10 ./old_version ./new_versionhyperfine会自动做预热和多次运行最后给出每个命令的平均值、标准差、以及两者之间的相对快慢。有了它你就不需要自己写循环计时的脚本。后面我们继续用它来验证 Claude 的改动。3. 三个实测案例Claude 的代码在基准测试里表现如何空谈理论没意思。我来分享几个最近实际跑过的案例全部围绕Claude 能写出更快的代码但它不能证明代码真的更快这个主题展开。3.1 C 语言文件读写理论更优实际要看 I/O 场景第一个案例是 C 语言的文件读写。我让 Claude 优化一段逐字符读取文件并计算所有字节之和的代码。原始版本大概是这样的long sum_fgetc(FILE *fp) { int c; long sum 0; while ((c fgetc(fp)) ! EOF) { sum c; } return sum; }Claude 给的版本是改用fread分批读入缓冲long sum_fread(FILE *fp) { unsigned char buf[8192]; size_t n; long sum 0; while ((n fread(buf, 1, sizeof(buf), fp)) 0) { for (size_t i 0; i n; i) { sum buf[i]; } } return sum; }从理论上讲fread比fgetc快是因为每次fgetc都可能触发一次标准库内部的函数调用而fread一次调用就能拿到大块数据减少了调用开销。这个推理没问题。但实测数字才有发言权。我在一台普通的 Linux 机器上、用-O2编译对同一个文件做了对比版本1MB 小文件1GB 大文件首次读取1GB 大文件已缓存fgetc约 7.1ms约 6.5s约 5.8sfread8KB 缓冲约 1.3ms约 1.1s约 0.7sfread版本在大文件下快得很明显但从 8KB 缓冲换成 64KB 缓冲差距又没那么大了。更关键的是如果文件在机械硬盘上两个版本的时间都会暴涨到几十秒因为真正的瓶颈在磁盘寻道不再是谁的调用次数少。这个案例说明Claude 的优化方向是对的但它不能替你回答你的文件到底多大、放在什么存储介质上。这些变量决定了最终收益。3.2 快速排序算法变了约束也跟着变了第二个案例是快速排序。我在测试时让 Claude 用 Python 写一个高性能快速排序它给了一个用列表推导式分区、递归排序的版本def quicksort(arr): if len(arr) 1: return arr pivot arr[len(arr) // 2] left [x for x in arr if x pivot] mid [x for x in arr if x pivot] right [x for x in arr if x pivot] return quicksort(left) mid quicksort(right)这段代码思路清晰在面试里可以得高分。但实测排序 10 万个随机整数时它比 Python 内置的sorted()慢了几十倍原因是内置sorted()是 C 语言实现的 Timsort而列表推导式版本要产生大量临时列表还要在 Python 层频繁递归。更有趣的是如果拿一段本来就接近有序的数据去测sorted()依然飞快而上面这个快速排序反而可能退化。这里的问题不是Claude 写错了而是当 Claude 给出更快的代码时你必须同时问一句它是在什么指标上更快如果只是比较两个 Python 快排实现它可能确实更快如果和内置函数比它完败如果题目要求必须手写快排那用sorted()根本不算数。3.3 Python 量化策略代码向量化不是万能钥匙第三个案例来自量化交易。有人让 Claude 优化一段 Python 策略回测代码原始版本用的是for循环逐行计算信号。Claude 的建议很标准转成 pandas/numpy 向量化操作。向量化当然有效尤其是当数据是几千行、几万行的 DataFrame 时处理速度能差出两个数量级。但我也遇到过一个反例数据只有几百行、单次回测只跑一个标的此时每次向量化操作都要新建数组、计算临时对象内存分配的开销反而盖过了计算本身。我实测过对这种小数据量的场景简单循环和向量化差距已经小于 1 倍有些边界情况下循环甚至更快。这个案例给我们的启示是Claude 根据一般规律给出的优化建议可能只在数据量达到某个阈值后才成立。你需要自己确定那个阈值。3.4 顺便聊聊 Julia 和 Windows 游戏优化脚本热词里还出现了 Julia 性能优化与内存管理。这类系统级语言里Claude 可能会生成带inbounds、simd宏的 Julia 代码也可能建议你用多线程并行。这些宏确实能提速但它们会绕过边界检查如果索引越界程序可能直接崩溃而不是报错。它不会因为你用 AI 生成代码就免掉这个问题。另外热词里还有用 bat 批处理优化 Windows 游戏性能这类需求。让 Claude 写一段关闭后台服务、调整电源模式、清理临时文件的批处理脚本本身没什么问题但这类脚本影响的是整个操作系统的状态不是单次程序运行。你在自己机器上感觉变快了可能是心理作用也可能是这次本来就比较空闲。要验证这种优化至少要在固定场景下用帧数记录工具多测几局游戏而不是跑一次就算数。4. 为什么看起来更快的代码一测就翻车我见过很多开发者卡在Claude 说会更快结果测出来没变化这个阶段。这不一定是你不会写 benchmark也可能是基准测试本身被一些隐藏因素干扰了。4.1 编译器与解释器的隐藏动作C/C 在-O0下代码逻辑清晰但指令低效到了-O2编译器可能自动做内联、循环展开、常量折叠。如果你拿一个未经优化的 Claude 版本和一个已经完善的原始版本对比结果可能只是编译器优化级别不同跟代码写法关系不大。反过来某些看起来更快的手写优化反而会阻止编译器做自动优化。比如你手动展开循环、手动拆解结构体编译器可能就无法再生成它本来会更擅长的 SIMD 指令了。我用-O3实际测过一些案例手写优化的 C 代码常常和原始代码打平甚至更慢。4.2 缓存、频率、垃圾回收这些噪声现代 CPU 的缓存对性能影响极大。同一个函数热数据在 L1 缓存里可能只要几纳秒从内存里读就是上百纳秒。如果你的新旧方案改变了数据访问顺序测量结果里有一大半是在测缓存命中率。热词里提到的移动端性能优化、安卓性能优化也是同一个道理。App 的卡顿经常和主线程排队、GPU 渲染管线、网络加载有关单纯优化一段排序代码对整体体验影响可能很小。Claude 看不到你 App 的完整运行链路它只能对局部代码做改进。除此之外Python/Java/Go 这类带垃圾回收或 JIT 的语言第一次运行和第二次运行的耗时可能完全不同。JIT 需要预热GC 可能在某一轮突然触发。所以跑 benchmark 时前几轮结果直接丢弃等稳定了再记录是基本操作。4.3 基准测试本身可能测错还有一种常见情况基准代码本身没写好。比如编译器发现计算结果没被使用直接把整个计算优化掉了那么你测的就是一个空壳又比如time命令输出被程序的日志输出污染第一眼看到的 CPU 时间其实是浪费在打印上了。为了避免这种问题至少要确保输入数据有足够规模并且把计算结果做个 hash 校验防止编译器或解释器把无用计算删掉。更简单的办法是让程序的输出包含一个基于全部数据的汇总值并把它写到/dev/null或丢弃。5. 一套可以直接复用的验证流程经过多次踩坑我总结了一套固定流程。现在每次拿到 Claude 的优化代码我都会走一遍再决定要不要合入。5.1 先写基准测试再写优化正确的顺序是先把当前代码的基准测试跑出来再让 Claude 优化。很多人反着来先让 Claude 优化最后才想起来要对比结果发现自己根本没保存原始版本的时间。我把这个过程写成了一个简单 check list确定测试数据和输入规模确保它能代表生产环境。先运行原始版本 5 到 10 次记录平均耗时和波动范围。用hyperfine或等价工具做后续对比手动time适合快速一瞥不适合严谨对比。每次只改一个变量要么只换算法要么只换编译器选项不要同时引入两个改动。验证新旧输出是否一致最好对结果做 checksum。在至少两种不同输入规模下测试避免只测一个点。5.2 把 Claude 变成并列实验设计者我现在的用法是让 Claude 生成一段 benchmark 脚本而不是直接让它给出哪个更快的结论。比如我可以这样问帮我把这个 C 程序写成一个支持多轮测试的 benchmark能统计每轮耗时、平均值和标准差分别用-O0和-O2编译接收一个测试文件路径作为参数。这样 Claude 在帮我建跑道它写的 benchmark 代码运行在固定框架下真实数据会替我做裁判。等 benchmark 脚本本身被验证无误后再让 Claude 提供多个优化版本一并对跑。5.3 用数据而不是感觉做结论最后一步是看数据。hyperfine会输出类似这样的结果Benchmark 1: ./old_version Time (mean ± σ): 786.4 ms ± 12.1 ms [User: 310.2 ms, System: 474.5 ms] Range (min … max): 771.3 ms … 803.0 ms 10 runs Benchmark 2: ./new_version Time (mean ± σ): 402.7 ms ± 8.3 ms [User: 191.8 ms, System: 209.4 ms] Range (min … max): 392.1 ms … 418.2 ms 10 runs Summary ./new_version ran 1.95 ± 0.05 times faster than ./old_version注意不要只看平均值。标准差太大说明测量环境不稳定此时应该增加运行次数、关闭后台任务、或者改用更稳定的测试机。如果两个版本的耗时分布重叠严重即使平均值看起来差了 5%也不能贸然说新版更快。6. 我和 Claude 配合做性能优化的几个工作习惯工具会越来越强Claude Code 这类编程助手也确实能显著提高写代码和重构效率但在性能优化这件事上我的分工方式一直很明确Claude 负责出方案、写辅助脚本、解释原理我负责定实验、看数据、做最终决策。6.1 让 Claude 先回答是什么在慢而不是怎么变快直接问怎么让这段代码变快得到的答案往往是泛泛的。更好的方式先让它分析代码指出可疑点再帮你写测量代码。把问题改一改质量会高很多这段 Python 代码跑得很慢请先帮我列出最可能导致慢的 5 个原因并给出每一个原因对应的验证方法。这样它给出的就不是一条未经证实的优化建议而是一组可以靠实验验证的假设。验证完哪个假设成立再去优化那部分。6.2 对 Claude 说清楚你的约束和场景Claude 不知道你的目标平台、数据量、编译器版本所以你必须喂给它这些信息。我在提示词里固定会写清楚语言和版本Python 3.11C11Julia 1.10。编译选项-O2或 Python 的--enable-shared。输入规模单文件 500MB或数组长度 10 万。允许改动范围只能动核心函数不能换数据库不能引入第三方依赖。正确性约束输出必须保持完全一致。这些约束写清楚后Claude 给出的代码会更贴合实际环境也更少出现推荐了一个你根本不能用的重型框架这种尴尬。6.3 我对AI 帮你优化代码的真实看法我仍然会用 Claude 来写和改代码。它尤其在代码审查、解释晦涩逻辑、生成胶水代码、写测试用例这些方面非常高效。但我不再相信它自带的那种自信语气。回头看“Claude 能写出更快的代码但它不能证明代码真的更快”这句话其实不是对 AI 的批评而是对所有工程判断的提醒。任何老程序员给你优化意见你也得验证任何博客上的 benchmark 曲线你也得在自己的数据上复现。AI 只是把这个过程变得更频繁、更方便了并没有免除你的实验责任。所以我最后想分享的实操建议特别简单让 Claude 写一个 benchmark 夹具把新旧代码放进去跑一遍再把结果发给它看。你会发现当 Claude 能看到真实数字时它接下来的建议会明显更有分寸甚至会主动告诉你这个优化在当前数据量下收益不大别改。这才是人和 AI 协作做性能优化该有的样子一个负责创造可能一个负责判断真实。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。