mcpField
P
performance-optimization

performance-optimization

github.com/rogervila开发053 次安装1 天前更新
代码仓库

关于 performance-optimization

面向编码 Agent 的可复用性能优化 Skill,涵盖目标定义、热点定位、行为验证和效果测量。它强调以证据驱动改动,并以正确性、安全性和可维护性为边界。

主要功能

  1. 01性能目标触发条件
  2. 02基线与工作负载评估
  3. 03基于分析的瓶颈定位
  4. 04保持行为的优化流程
  5. 05优化后测量与权衡记录

适用场景

  1. 01排查延迟或吞吐量回退
  2. 02降低高频代码的内存占用
  3. 03审查数据库、I/O 或并发瓶颈

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rogervila/agent-skills --skill performance-optimization

安装后在 Claude Code 中输入/performance-optimization确认已加载。

附带文件assets/behavior-fixtures.jsonscripts/validate-fixtures.js

详细介绍

性能优化

当性能是明确目标或存在明显风险时,请使用此技能:例如延迟、吞吐量、内存、CPU、启动时间、构建时间、I/O、数据库负载、并发或可扩展性。目标是在不改变可观察行为的前提下,让代码运行更快或占用更少资源;只要可行,就通过测量验证改进效果。

性能是首要设计约束,但正确性、安全性和可维护性仍是不可逾越的边界。在清晰度相当时,优先选择高效方案。只有在已测得的热点路径或高风险工作负载中,才采用侵入式重写、巧妙的微优化和增加复杂度的做法。

触发条件

当任务包含以下情况时,请使用此技能:

  • 明确提及性能的术语,例如优化、加速、缓慢、瓶颈、延迟、吞吐量、内存、分配、CPU、热点路径、可扩展性、基准测试、分析、N+1、缓存或并发。
  • 代码频繁运行、处理大量数据、处于请求/构建/渲染循环中,或反复执行 I/O 或数据库操作。
  • 审查某个实现时,算法复杂度过高、分配过多、I/O 阻塞、并发无上限或资源泄漏可能造成实际成本。
  • 在其他方面相似的实现中进行选择,且其中一种明显更高效,同时不会明显损害可读性或正确性。

以下情况不应以此技能作为主要考量:

  • 用户只要求调整格式、命名、文档、产品文案或代码风格。
  • 代码用于一次性设置、迁移、测试数据生成或管理脚本,且未提出性能方面的顾虑。
  • 某项更改会为了推测性的速度而牺牲正确性、安全性、无障碍性、兼容性或清晰的仓库约定。
  • 仓库中已有功能缺陷,但没有证据表明根因是性能问题。

必需输入和前提

优化前,应尽可能收集以下信息:

  • 性能目标或症状:目标延迟、吞吐量、内存上限、CPU 限制、超时时间、构建时长或用户可感知的卡顿。
  • 工作负载特征:输入规模、调用频率、数据分布、并发级别、运行环境,以及路径受 CPU 限制还是 I/O 限制。
  • 基准数据:分析器输出、基准测试结果、日志、查询计划、跟踪记录、火焰图、复现步骤,或可在本地运行的小型基准测试。
  • 必须继续满足的正确性要求和现有测试。
  • 仓库约束:语言/运行时版本、框架约定、支持的平台、依赖项和部署限制。

如果没有基准数据,在实际可行时,应创建有针对性的测量。如果无法测量,应说明所采用的假设,并选择风险较低、且有复杂度分析依据或明显可消除冗余工作的改动。

优化工作流

  1. 定义指标。 明确需要改善什么,以及哪些指标不能退化。
  2. 找到热点路径。 结合工作负载频率,通过性能分析、追踪、查询计划、日志或代码检查定位热点。
  3. 保持行为不变。 在更改高风险逻辑前,运行或添加针对性正确性测试。
  4. 选择收益最高的修复方案。 优先考虑算法改进、批处理、减少分配、流式处理、索引、缓存或有界并发,而非表面上的微调。
  5. 控制改动范围。 针对瓶颈进行优化,避免大规模重写或无关重构。
  6. 再次测量。 使用相同的工作负载比较优化前后的数据;如果只能进行静态验证,请说明原因。
  7. 记录权衡。 说明优化带来的复杂性、缓存失效问题、并发限制或环境假设。

编写代码前,停下来问问自己:

  1. 对于此工作负载,主要开销是什么?
  2. 我能否降低算法复杂度、减少分配、I/O 往返、阻塞或争用?
  3. 我将如何验证此次更改没有改变行为,并且确实改善了目标指标?

1. 循环与迭代

每个循环都会放大开销。尽量减少循环体内的操作。

  • 不要在循环内重复计算不变量。 将常量表达式、长度和查找操作移到循环外。
  • 如果用哈希表或索引就能一次遍历完成,就避免嵌套循环。 有 O(n) 或 O(n log n) 的方案时,几乎不应接受 O(n²)。
  • 优先使用语言原生的批量操作(map、filter、reduce、列表推导式、向量化操作),前提是运行时会对其进行优化。
  • 尽早退出。 找到答案后就停止迭代。使用 break、提前返回或短路求值。
  • 合并循环。 如果两个连续循环遍历同一集合,且逻辑允许,就将它们合并为一次遍历。
  • 避免在循环内分配内存。 不要在循环体内创建可在循环开始前创建并复用或预分配的对象、字符串或数组。
// BAD — recomputes len, creates string each iteration
for (int i = 0; i < list.size(); i++) {
    String key = prefix + ":" + list.get(i).getName();
    map.put(key, list.get(i));
}

// GOOD — hoisted size, reused builder, single access
int n = list.size();
StringBuilder sb = new StringBuilder(prefix).append(':');
int prefixLen = sb.length();
for (int i = 0; i < n; i++) {
    Item item = list.get(i);
    sb.setLength(prefixLen);
    sb.append(item.getName());
    map.put(sb.toString(), item);
}

2. 变量与临时值

每个变量都会占用寄存器或栈空间。只使用必需的变量。

  • 消除不必要的临时值。 如果某个值只使用一次,且内联后仍易于阅读,就直接内联。
  • 不要给从不读取的变量赋值。 无用的写入会浪费周期,也会让读者困惑。
  • 表达式清晰时,优先直接返回,而不是先赋值给临时变量再返回。
  • 复用累加器,不要构建马上就会被丢弃的中间集合。
// BAD — pointless temporary
result = compute_value(x)
return result

// GOOD — direct return
return compute_value(x)
// BAD — builds full list just to check existence
temp = [item for item in collection if item.matches(criteria)]
found = len(temp) > 0

// GOOD — short-circuit, no allocation
found = any(item.matches(criteria) for item in collection)

3. 内存与分配

内存分配开销很高。最快的分配,就是从未发生的分配。

  • 预分配大小已知或可估算的集合。调整数组、列表或映射的大小代价高昂。
  • 重复执行操作时复用缓冲区(用于字符串构建、字节缓冲区和临时数组)。
  • 当生命周期仅限于当前作用域时,优先使用栈分配而非堆分配(值类型、结构体、栈数组)。
  • 在区分装箱与非装箱类型的语言中,避免对基本类型进行装箱(Java、C#、Kotlin)。
  • 在性能关键路径中,对高频、短生命周期的分配使用对象池或内存区域分配器。
  • 优先使用视图或切片,而非复制子数组或子字符串。无需修改时,直接引用原始数据。
  • 尽早释放引用。 大对象不再需要时,应尽快将其引用置空或重新赋值,尤其是在长时间运行的操作开始前。
  • 选择合适的数据结构容量。 如果已知要存储 10,000 个条目,就不要使用默认容量为 16 的 HashMap<K,V>。
// BAD — grows the list dynamically, multiple reallocations
items = []
for row in rows:
    items.append(transform(row))

// GOOD — pre-allocated
items = [None] * len(rows)
for i, row in enumerate(rows):
    items[i] = transform(row)

// BEST — generator if downstream consumes lazily
items = (transform(row) for row in rows)

4. 算法和数据结构

最大的性能提升来自选择正确的算法,而不是对错误的算法进行微调。

  • 了解复杂度。 编写解决方案之前,先说明其时间和空间复杂度的 Big-O。如果复杂度高于必要水平,就寻找更好的方法。
  • 使用基于哈希的查找(集合、映射、字典)进行成员测试和键查找——时间复杂度为 O(1),而线性扫描为 O(n)。
  • 只在需要时排序,并选择合适的排序方式。不要为了查找最小值或最大值而排序——只需扫描一遍。
  • 使用合适的数据结构:双端队列适用于两端操作,堆适用于 top-k,字典树适用于前缀匹配,位集适用于标志。
  • 缓存开销大的计算。 对输入重复的纯函数使用记忆化。对常量映射使用查找表。
  • 避免重复计算。 在同一作用域内,绝不要重复计算相同的派生值。计算一次,保存并复用。

5. 字符串操作

字符串的开销往往超乎意料。拼接、格式化和编码都是容易被忽视的成本来源。

  • 多步拼接时使用字符串构建器/缓冲区,尤其是在循环中。绝不要在循环中使用 + 拼接。
  • 优先使用插值或格式化,前提是该语言能对其进行优化。
  • 避免重复解析。 将字符串解析一次(转换为日期、数字、枚举等),然后传递解析后的值。
  • 如果可使用驻留字符串或符号,先比较标识再比较相等性。
  • 不需要 Unicode 语义时使用字节级操作(例如,解析 ASCII 协议)。

6. I/O 和网络

I/O 比计算慢几个数量级。应批量处理、使用缓冲,并尽量减少往返次数。

  • 批量执行数据库查询。 绝不要在循环内查询(N+1 问题)。使用批量获取、JOIN 或 IN 子句。
  • 使用 I/O 缓冲。 用带缓冲的包装器包装无缓冲流。合理地刷新缓冲区,而不是每次写入都刷新。
  • 尽量减少网络往返。 合并 API 调用,使用批量端点,并预先获取所需内容。
  • 处理大型负载时使用流式传输,而不是将所有内容都加载到内存中。
  • 为数据库、HTTP 客户端以及任何可复用的连接使用连接池。
  • 设置适当的超时时间。 无限期等待会浪费线程和资源。
  • 对大型结果集进行分页,而不是将数百万行加载到内存中。
// BAD — N+1 queries
for user in users:
    orders = db.query("SELECT * FROM orders WHERE user_id = ?", user.id)

// GOOD — single batch query
user_ids = [u.id for u in users]
all_orders = db.query("SELECT * FROM orders WHERE user_id IN (?)", user_ids)
orders_by_user = group_by(all_orders, key=lambda o: o.user_id)

7. 并发和并行化

I/O 密集型工作使用并发,CPU 密集型工作使用并行。要了解两者的区别。

  • 找出相互独立的操作并并发运行(async/await、futures、goroutines、线程)。
  • 对可以重叠执行的网络调用、文件读取和数据库查询使用异步 I/O。
  • 使用线程池、工作池或并行流,将 CPU 密集型工作分配到多个核心上——但只有在工作负载足以抵消开销时才这样做。
  • 避免共享可变状态。 优先使用不可变数据、消息传递或无锁结构。如果必须加锁,应尽量缩小临界区。
  • 使用有界并发批量处理并发任务(信号量、任务队列),避免资源不堪重负。
  • 使用并行数组或相邻的原子计数器时,注意缓存行上的伪共享。
// BAD — sequential I/O calls
result_a = await fetch(url_a)
result_b = await fetch(url_b)
result_c = await fetch(url_c)

// GOOD — concurrent I/O
[result_a, result_b, result_c] = await Promise.all([
    fetch(url_a),
    fetch(url_b),
    fetch(url_c),
])

8. 惰性求值和短路求值

不要计算用不到的内容。

  • 在使用方可能不需要全部结果时,使用惰性求值(生成器、迭代器、流)。
  • 根据开销和触发概率安排条件判断顺序。 将开销最低且最可能触发短路的检查放在最前面。
  • 延迟开销大的初始化操作,直到实际访问该值时再执行(惰性属性、双重检查锁定、once 模式)。
  • 在查询中使用分页和限制——不要为了显示十行而获取所有行。
// BAD — evaluates expensive condition even when cheap one fails
if (expensiveCheck(x) && cheapCheck(x)) { ... }

// GOOD — cheap check first, expensive only if needed
if (cheapCheck(x) && expensiveCheck(x)) { ... }

9. 缓存

最快的计算,就是已经完成的计算。

  • 缓存纯函数的结果,以应对重复输入(记忆化)。
  • 采用合适的缓存淘汰策略(LRU、TTL、大小限制),防止内存无限增长。
  • 在合适的层级进行缓存。 热点数据存于内存,共享状态使用 Redis/Memcached,API 响应使用 HTTP 缓存,静态资源使用 CDN。
  • 正确地使缓存失效。 过期缓存比没有缓存更糟。对于允许一定程度过期的数据,优先使用基于时间的过期策略。
  • 先分析性能,再进行缓存。 只缓存实际开销较大的内容。缓存廉价计算只会增加复杂度,却没有收益。

10. 数据序列化与反序列化

在每个边界解析和格式化数据,都会产生隐性开销。

  • 选择合适的格式。 对于内部服务通信,二进制格式(Protocol Buffers、MessagePack、FlatBuffers)比文本格式(JSON、XML)更快。只有在系统边界需要人工可读性时,才使用文本格式。
  • 只序列化一次。 不要将对象转换为 JSON,在传递字符串后,又在同一进程的另一端将其解析回来。直接传递对象。
  • 对于大型负载,使用流式解析器(SAX、JsonReader、ijson),而不是将整个文档载入 DOM 树。
  • 避免重复序列化。 如果同一个对象要被序列化多次(例如用于日志和响应),只序列化一次并重复使用结果。
  • 在性能关键路径中,优先使用由架构驱动的序列化(protobuf、Avro),而不是基于反射的序列化(Java 默认的 Serializable、Python 的 pickle)。
  • 注意编码开销。 Base64 编码会使数据膨胀约 33%。当负载大小很重要时,先压缩再编码。
  • 按需反序列化。 如果只需要一个含有 50 个字段的 JSON 对象中的 3 个字段,请使用部分解析器或投影,不要反序列化整个对象。
// BAD — full deserialization when only one field is needed
data = json.parse(payload)
user_id = data["user"]["id"]

// GOOD — targeted extraction (language-dependent)
user_id = json_extract(payload, "$.user.id")

11. 错误处理

异常开销很大。绝不要将其用于控制流。

  • 不要针对预期情况抛出异常。 用户提交无效输入并非异常情况,而是正常情况。请使用结果类型、错误代码或验证返回值。
  • 避免在热点循环中使用 try/catch。 在大多数运行时中,进入 try 块会产生开销,而抛出异常的代价极高(栈展开、捕获跟踪信息)。
  • 优先使用守卫子句(对无效输入提前返回),而不是用 try/catch 包裹整个方法。
  • 对于允许这样做的语言,已知错误类型可禁用栈跟踪(例如,在 Java 中重写 fillInStackTrace()),前提是从不读取跟踪信息。
  • 在性能关键代码中,使用错误值模式(Result<T, E>、Option<T>、(value, err) 元组),而不是基于异常的流程。
// BAD — exception as control flow in a tight loop
for item in items:
    try:
        value = int(item)
        process(value)
    except ValueError:
        continue

// GOOD — check before converting
for item in items:
    if item.isdigit():
        process(int(item))

12. 日志记录与可观测性

日志开销无形无迹,直到它占据了性能分析结果的大头。

  • 为开销较大的日志消息添加保护。 如果日志级别已禁用,不要构造日志消息字符串。使用惰性求值、lambda 或级别检查保护。
  • 除非处于 TRACE/DEBUG 级别且经过级别检查保护,否则不要在紧密循环中记录日志。
  • 优先使用结构化日志(键值对),而不是字符串格式化。结构化日志记录器会延迟序列化,直到日志实际写入时才进行。
  • 对于高吞吐量路径,使用异步/缓冲日志。同步写入磁盘或网络会阻塞调用线程。
  • 避免记录大型对象。 不要在 INFO 级别对整个集合或请求正文调用 toString()。应改为记录标识符和大小。
  • 对高频事件进行采样。 如果某个事件每秒触发数千次,就按 N 次取 1 次记录,而不是记录每次发生。
// BAD — string is always constructed, even if DEBUG is off
logger.debug("Processing user " + user.toString() + " with orders " + orders.toString())

// GOOD — deferred evaluation, no construction if level is off
logger.debug("Processing user {} with {} orders", user.id, orders.size())

13. 正则表达式

正则表达式功能强大,但其开销往往容易被低估。请使用能解决问题的最简单工具。

  • 编译一次,重复使用。 切勿在循环内或每次调用函数时编译正则表达式模式。请将其编译为常量、static final 或模块级变量。
  • 优先使用简单的字符串方法(startsWith、endsWith、contains、indexOf、split),适用于字面匹配或非常简单的情况。
  • 避免灾难性回溯。 (a+)+ 或 (a|a)+ 之类的嵌套量词会导致时间复杂度呈指数级增长。可用时,请使用原子组或占有量词。
  • 无需获取匹配值时,请使用非捕获组 (?:...),而不是捕获组 (...)——捕获会分配内存。
  • 为模式添加锚点。 使用 ^ 和 $ 锚点,避免引擎不必要地扫描整个字符串。
  • 将复杂模式与手写解析器进行基准测试。 对于高频解析(日志、协议),状态机的性能通常优于正则表达式。
// BAD — recompiles regex on each call
def extract_email(text):
    match = re.search(r'[\w.+-]+@[\w-]+\.[\w.-]+', text)
    return match.group(0) if match else None

// GOOD — compiled once at module level
EMAIL_PATTERN = re.compile(r'[\w.+-]+@[\w-]+\.[\w.-]+')

def extract_email(text):
    match = EMAIL_PATTERN.search(text)
    return match.group(0) if match else None

14. 资源生命周期

资源泄漏会导致性能缓慢退化。

  • 打开什么,就一定要关闭什么。 使用语言提供的模式:try-with-resources(Java)、using(C#)、with(Python)、defer(Go)、RAII(C++/Rust)。
  • 严格控制资源的作用范围。 尽可能晚地打开文件、数据库连接或锁,并尽可能早地释放。不要在长时间运行的操作期间一直持有资源。
  • 避免使用终结器和析构函数进行清理。 它们的运行时机不可预测(甚至可能永远不运行),还会增加 GC 开销。请使用确定性的清理方式。
  • 留意连接泄漏。 每个未归还的数据库连接、HTTP 客户端或套接字都会耗尽连接池,最终导致所有操作停滞。
  • 限制资源消耗。 使用有界队列、速率限制、最大连接数和内存上限,防止资源不受控制地增长。
// BAD — connection leak if process() throws
conn = pool.get_connection()
result = process(conn)
conn.close()

// GOOD — guaranteed cleanup
with pool.get_connection() as conn:
    result = process(conn)

15. 数据局部性与缓存友好性

最快的数据,就是已经位于 CPU 缓存中的数据。

  • 按顺序访问内存。 由于缓存预取,线性遍历数组的速度远快于沿着指针遍历链表或树。
  • 将热点数据放在一起。 将一起访问的字段放入同一个结构体或对象中。将很少访问的字段放入辅助结构。
  • 当遍历顺序可预测时,优先使用数组/向量而非链式结构(链表、每个节点都通过指针连接的树)。
  • 处理多个实体中的同一字段时,考虑使用 SoA(结构体数组)而非 AoS(数组结构体)(常见于数据密集型代码或游戏/模拟代码)。
  • 尽量减少指针间接寻址。 每次沿指针访问都可能导致缓存未命中。在可行时,将嵌套对象扁平化。
  • 注意内存对齐和填充。 在可控制内存布局的语言中,按大小(从大到小)排列结构体字段,以尽量减少填充浪费。
  • 使用连续分配。 为一同创建和处理的对象预先分配扁平缓冲区或内存区域。
// SLOW — random access pattern, poor locality
for node in linked_list:
    total += node.value     // each node is a pointer chase

// FAST — sequential access, cache-friendly
for i in range(len(values)):
    total += values[i]      // contiguous memory, hardware prefetch

16. 语言特定注意事项

了解所用语言的性能特征。

这项技能与语言无关,但在相关情况下,Agent 必须运用特定语言的知识:

  • JVM(Java、Kotlin、Scala): 避免自动装箱,优先使用基本类型流,留意 GC 压力,使用 StringBuilder,选择合适的集合实现。
  • Python: 优先使用生成器而不是列表,优先使用 collections 模块中的类型,使用 NumPy/pandas 进行向量化计算;避免使用全局解释器锁实现 CPU 并行(改用多进程)。
  • JavaScript/TypeScript: 避免多态性过高的调用点,数值计算优先使用类型化数组,CPU 密集型任务使用 Web Workers,留意事件循环阻塞。
  • Go: 尽量减少逃逸到堆上的分配,使用 sync.Pool 复用对象,小型结构体优先使用值接收者,使用有并发上限的 goroutine。
  • Rust: 优先使用栈分配,使用迭代器而不是索引循环,避免不必要的克隆,充分利用零成本抽象。
  • C/C++: 考虑缓存局部性(结构体数组 vs 数组结构体),适用时使用 SIMD,优先使用移动语义而不是复制,减少热点路径中的虚函数分派。
  • SQL: 使用索引,避免 SELECT *,使用 EXPLAIN 了解查询计划,优先使用基于集合的操作而不是游标。
  • PHP: 优先使用原生数组函数而不是手动循环,使用生成器处理大型数据集,避免不必要的对象实例化,有效使用 opcache。
  • C#/.NET: 使用 Span<T> 和 Memory<T> 避免分配,热点异步路径优先使用 ValueTask,使用 ArrayPool 处理临时缓冲区,避免在热点路径中使用 LINQ,以免产生委托开销。

17. 不应优化的情况

过早优化是万恶之源,但故意忽视性能问题也同样有害。

在以下情况下,不要以牺牲可读性为代价进行微优化:

  • 代码只运行一次(脚本、迁移、设置)。
  • 操作耗时已经不到 1 毫秒,且不在热点路径中。
  • 性能分析显示瓶颈在其他地方。

但在以下情况下,始终应进行优化:

  • 代码在循环、请求处理程序或热点路径中运行。
  • 操作涉及 I/O、网络或大量数据。
  • 高效与低效的写法可读性相当(默认优先选择高效写法)。
  • 可以使用更好的算法或数据结构,且不会增加复杂性。

应用此技能

编写或审查代码时,请遵循以下清单:

  1. 找出热点路径。 这段代码最常在哪里运行?
  2. 选择合适的算法。 对这个问题来说,Big-O 复杂度是否最优?
  3. 尽量减少分配。 能否预先分配、复用或避免创建对象?
  4. 消除冗余工作。 是否有重复计算?能否缓存结果?
  5. 批量处理 I/O。 是否进行了不必要的磁盘、网络或数据库往返?
  6. 利用并发。 是否有可以并行运行的独立操作?
  7. 尽早短路。 能否提前退出循环、条件判断或函数?
  8. 为日志添加防护。 是否在检查日志级别后才构造日志消息?
  9. 只序列化一次。 是否在不同边界间进行了不必要的数据来回转换?
  10. 低成本地处理错误。 是否在热点路径中使用异常控制流程?
  11. 关闭资源。 是否确定性地释放连接、句柄和锁?
  12. 考虑局部性。 数据布局是否适合访问模式,有利于缓存?
  13. 用数据验证。 如有疑问,请进行性能分析。不要凭猜测判断瓶颈所在。

每行代码都有成本。只有在工作负载值得时,才引入复杂性。

快速入门工作流

  1. 分析:使用性能分析工具或有依据的代码检查,找出热点路径、瓶颈和目标指标。
  2. 重构:应用效果最佳且改动最小的方案:优化复杂度、减少分配、批处理、流式处理、索引、缓存、限制并发或减少同步。
  3. 验证:运行正确性检查,并在可行时使用相同工作负载比较优化前后的性能。

验证与完成

满足以下条件时,表示此技能已成功应用:

  • 已说明目标指标和工作负载,或者 Agent 明确说明所采用的假设。
  • 已通过性能分析器数据、基准测试数据、查询计划、日志、跟踪记录或清晰的复杂度分析,识别出可能的瓶颈。
  • 实现保留了可观察到的行为,并且现有测试仍然通过。
  • 优化范围针对瓶颈,避免无关的重写。
  • 在可以进行测量时,报告优化前后的证据,包括命令、工作负载、样本数量和结果。
  • 如果基准测试噪声或环境限制导致结果不确定,最终回答应说明这一点,且避免夸大收益。

如有可用的现有性能工具,请使用仓库中的工具:基准测试套件、负载测试、性能分析器、数据库 EXPLAIN、火焰图、浏览器性能工具、内存分析器或运行时跟踪。除非该框架适合项目且用户要求持久化的性能测试,否则不要添加新的基准测试框架。

失败与升级处理

遇到以下情况时,应向用户请求澄清或停止操作,而不是猜测:

  • 目标工作负载、预期规模或性能指标至关重要,但尚不明确。
  • 拟议的优化会改变用户可见行为、数据一致性、顺序、安全性、无障碍访问或兼容性。
  • 唯一可行的改进方案需要架构变更、新基础设施、付费服务、架构迁移或承担运维风险。
  • 现有测试缺失,且代码路径风险过高,无法在未先添加正确性覆盖或请求用户提供覆盖的情况下进行优化。

如果用户的请求与性能无关,不要强行应用此技能。应优先遵循仓库的常规做法,同时在同样简单的情况下选择效率更高的代码。

输出要求

完成性能任务时,请包含:

  • 已处理的瓶颈或风险。
  • 所做的优化,以及它为何能改善目标指标。
  • 已运行的正确性检查。
  • 已运行的性能检查;如有结果,提供优化前后的对比。
  • 遗留风险、测量限制或后续性能分析目标。

参考文档

此技能遵循通用性能原则。目前不需要外部参考资料。

脚本和资源

  • assets/behavior-fixtures.json - 用于验证性能优化的启用、未启用、测量和验证指导的行为测试数据。
  • scripts/validate-fixtures.js - 验证此技能及其行为测试数据是否涵盖必需的性能优化边界。

许可信息

此技能根据 MIT 许可证 授权。

评论

支持 Markdown