Search: #性能瓶颈分析

  1. 《软件慢是因为设计差,不是因为语言慢》

    《软件慢是因为设计差,不是因为语言慢》

    标签:
    #软件工程 #性能优化
    #性能瓶颈分析 #IO密集型 #Amdahl定律 #AI辅助优化 #系统设计 #语言选型误区

    总结:
    这篇文章反驳了“用 AI 把软件重写成 C/Rust 就能变快”的流行观点。作者的核心论点是:大多数真实程序是 I/O 密集型的,性能瓶颈在数据库、网络和磁盘等待上,语言本身的执行速度只占很小一部分;即使遇到 CPU 密集型热点,慢语言也早已通过调用 C 级库(如机器学习中的矩阵运算)把重活外包了出去。真正有效的提速来自重新设计——缓存、异步、并行、消除 N+1 查询——而不是逐行翻译代码。

    文章要点:
    1. 大多数真实程序(尤其是 CRUD 类应用)是 I/O 密集型的:一次请求可能 50% 的时间花在数据库查询上,重写语言最多只能优化另外那 50%,按照 Amdahl 定律,整体提速上限约为 1.5~2 倍,远达不到数量级提升。
    2. 慢语言早已学会“外包”:Python 之所以能打机器学习这类 CPU 密集场景,是因为 NumPy 等库把矩阵运算下放到高度优化的 C/汇编甚至 GPU 上——如果程序 80% 时间在 GPU 上做矩阵乘,用 C 重写 Python 代码毫无意义。
    3. Bryan Cantrill 2018 年的经典案例佐证“设计 > 语言”:他把精心优化的 C 程序移植到 Rust 时借用检查器处处碰壁,改用“Rust 朴素写法”后反而快 30%——原因是 Rust 内部默认用 B 树而非二叉搜索树,缓存效率更高。
    4. 作者亲历的有效提速手段全部是设计层面的:缓存慢操作、异步化/后台任务、并行化、把 N 条 SQL 合成一条、用快查询替换慢查询、跳过不必要的操作——没有一条与语言速度有关。
    5. 慢语言反而可能更利于优化:高层语言代码一眼就能看出程序在做什么,更容易发现 N+1 查询或可异步化的 API 调用;如果先重写成汇编,这些结构性问题反而难以察觉。
    6. 少数真正 CPU 密集的热点(如 tiktoken 用汇编重写提速 5 倍)确实存在,但属于窄缝场景;而且这类提速往往也来自重新设计(去掉正则依赖),不是语言本身的功劳。
    7. 给 AI 时代的实用建议:别指挥智能体“把它重写成 C/Rust 来提速”,而要让它去分析火焰图、定位热点、提出重设计方案——语言重写只在极少数不可再简化的 CPU 密集热点处才值得动用。

    URL:https://seangoedecke.com/software-is-slow-because-of-bad-design-not-slow-languages/

  2. 《设计系统应该默认就是快的》

    《设计系统应该默认就是快的》

    标签:
    #前端开发 #设计系统性能优化 #性能测试 #性能预算 #WebComponents #组件渲染优化

    总结:
    这篇文章通过实测十大主流开源设计系统(Mantine、Ant Design、Material UI、React Spectrum、Carbon、Fluent、Web Awesome、UI5、Spectrum Web Components、Ionic),论证了性能应当与设计系统团队所重视的可达性(accessibility)平起平坐:底层组件的每一个性能修复,都会同时惠及所有基于该设计系统构建的应用。测试发现性能优劣并不取决于框架本身,而在于具体实现细节,作者还深入剖析了 Ionic、Ant Design、UI5、React Spectrum 等慢速组件的根因,并给出了可行的修复建议,最后提供了基于 Playwright 的自动化性能测试方案与「Fast by Default(默认即快)」的理念。

    文章要点:
    1. 浏览器的 JavaScript 主线程是所有层共用的,设计系统组件越慢,留给应用代码的余地就越小——修复一个设计系统组件的性能,等于同时提升所有依赖它的应用。
    2. 作者选取了十个基于不同框架(React、Lit、FAST、Stencil、SAP 自研框架)的设计系统,在 4 倍 CPU 降速、Chrome 155 环境下实测了两大典型场景:打开含 249 个国家的下拉选择器、一次性全选 100 个复选框。
    3. 实测结果差异巨大:国家选择器从最快 Fluent 的 61ms 到最慢 Ionic 的 1,266ms(比第二名慢 5 倍以上);复选框从 Fluent 的 29ms 到 Ant Design 的 421ms——同一框架(如 React 或 Lit)内部差距同样悬殊,性能问题出在实现而非框架。
    4. 十个设计系统中只有 Spectrum Web Components 在每个 PR 上自动跑组件级性能基准,多数团队只检查包体积——但包体积与组件在页面上的响应速度并无直接关系。
    5. 作者逐一剖析了慢速根因:Ionic 因 Stencil 在无 shadow DOM 的场景下用 appendChildSlotFix 模拟插槽、每次新增选项都要遍历全部既有子节点三次(O(n²));React Spectrum 因 React Aria 逐个清空高度再读取尺寸造成「布局抖动」;UI5 因隐藏弹层中预置全部 249 个选项,打开瞬间浏览器要一次性完成约 1500 个元素的样式计算;Ant Design 的慢则主要来自 100 个复选框同时触发的颜色渐变动画。
    6. 性能瓶颈各有解法:长列表用虚拟滚动(Ant Design 的做法值得借鉴,还为屏幕阅读器保留了高亮项的隐藏副本);动画改由合成器线程运行的 opacity 渐变替代主线程上的颜色渐变;Stencil 可直接修复插槽回退内容的第三次检查,作者实测去掉后加 2000 个元素快约 7 倍。
    7. 作者分享了用 Playwright + Chrome DevTools 协议(CPU 降速 4 倍 + Long Animation Frames 长帧 API)编写组件性能测试的完整代码,包含「总耗时预算 300ms」和「最长无响应帧不超过 100ms」两条性能预算(performance budget),以及一条「选项翻倍时耗时增长不超过 2.5 倍」的防 O(n²) 回归测试。
    8. 落地的最佳实践是「默认就提供快的行为」:超过性能预算的列表自动切换虚拟化、复选框仅在被直接点击时才播放动画,并在文档中写明每个组件的测试数据规模上限,发布说明中给出修复前后的量化数据(如「500 个选项下打开从 300ms 降到 150ms」)。
    9. 以上测试代码已开源在 GitHub 仓库 design-system-performance-tests 中,可直接复制改造用于自己的设计系统,并附带 GitHub Actions 工作流实现每个 PR 自动跑性能测试。
    10. 文章结尾宣传了作者的新书《Fast by Default: Practical Performance Engineering》(Manning 早期访问版),把这套思路延伸到后端与移动端。

    URL:https://denodell.com/blog/design-systems-should-be-fast-by-default Design Systems Should Be Fast by Default

  3. 《浏览器主线程很昂贵:高性能前端优化实战指南》

    《浏览器主线程很昂贵:高性能前端优化实战指南》

    标签:
    #前端 #Web性能 #浏览器原理 #JavaScript #渲染管线 #WebWorker #动画优化 #交互优化 #性能调优

    总结:

    本文深入剖析了浏览器主线程作为稀缺资源的工作原理,指出前端性能问题的根源往往不是代码速度慢,而是主线程被长时间占用导致界面冻结。文章系统性地介绍了两大类优化策略:在主线程上"精打细算"(拆分、批处理、优先级排序、延迟执行),以及"完全不用主线程"(利用合成器线程、Web Worker、消除不必要的工作),并通过大量交互式 Demo 帮助读者直观理解每种技术的实际效果。

    文章要点:

    1. 主线程是性能瓶颈的核心:主线程同时负责运行 JavaScript、样式计算、布局、绘制和事件处理,所有工作排队串行执行。60Hz 屏幕每帧预算约 16.6ms,实际可用仅约 10ms,超过 50ms 的任务会导致界面卡顿。

    2. 拆分(Splitting):将大任务切割成小片段,通过 setTimeout 或 requestAnimationFrame 让出主线程,让浏览器在间隙处理渲染和输入。注意过度拆分会产生额外开销,且 JSON.parse 等原子操作无法拆分。

    3. 批处理(Batching):将频繁触发的事件(如滚动、输入)合并执行,使用防抖(debounce)和节流(throttle)减少重复劳动。React 的虚拟 DOM 本质上也是一种批处理机制。

    4. 优先级排序(Prioritizing):通过自定义队列(基于 MessageChannel)实现任务插队机制,确保用户当前关注的操作(如点击预览图片)优先执行,采用"空闲时预处理,紧急时优先处理"的策略。

    5. 延迟执行(Deferring):非必要工作延后处理,包括代码分割、使用 IntersectionObserver 实现虚拟列表(只渲染可视区域内容)、离屏时暂停动画等,避免一次性处理全部数据。

    6. 利用合成器线程:使用 transform 和 opacity 代替 top、left、width 等触发布局的属性做动画,让动画在合成器线程运行,即使主线程繁忙也能保持流畅。

    7. FLIP 动画技术:对于必须改变布局的动画(如列表重排),先测量初始和最终位置,通过反转和播放 transform 来实现平滑过渡,将布局计算限制为仅一次,动画过程交给合成器。

    8. Web Worker 处理重计算:将图片处理、大数据解析等纯计算任务转移到 Worker 线程,通过 postMessage 的 Transferable 对象(如 ArrayBuffer)实现零拷贝数据传输,避免主线程冻结。

    9. 消除不必要的工作:当数据流入速度超过处理能力时,采用丢弃(旧日志)、合并(只保留最新值)、跳过(缓存 memoization)三种策略,从源头减少工作量。

    10. 避免布局抖动(Layout Thrashing):不要交替读写布局属性(如 offsetWidth),应先批量读取再批量写入,强制浏览器反复计算布局会严重阻塞主线程。

    URL:
    https://kciter.so/posts/the-expensive-main-thread/en/ The Browser's Main Thread Is Expensive | kciter.so