
# 性能

shikiphp 使用纯 PHP 进行真正的 TextMate 分词，因此需要如实说明它在哪些情况下速度快、哪些情况下速度不快。

## 性能表现

每个文件预计耗时数十到数百毫秒，而非微秒。分词器会缓存已编译的规则和扫描器，语法按需加载（从未涉及嵌入式语言的示例无需支付解码开销），大多数语法模式会通过经过等价性验证的 PCRE 快速路径使用原生 `preg_*`，其余部分则由纯 PHP 匹配器处理（参见 [架构](https://shikiphp.inline0.dev/zh/docs/architecture#the-scanner-and-its-pcre-fast-path)）。

以下是仓库基准测试（`bench/bench.php`，主题 `github-dark`）在一台机器上测得的预热后单次调用耗时，语料文件约有 55 到 105 行：

| 语法 | PHP 8.2 | PHP 8.4 |
| --- | --- | --- |
| JSON, YAML | 30–65 ms | 25–45 ms |
| CSS, HTML | 100–120 ms | 80–100 ms |
| Python, Rust, Go, Bash, Markdown | 190–220 ms | 125–175 ms |
| PHP | 约 290 ms | 约 170 ms |
| TypeScript, TSX | 490–510 ms | 310–370 ms |

进程中首次调用某种语言时，还需支付一次性的语法加载和编译开销：在同一批运行中，JSON耗时 50–70 ms，Markdown则略超一秒。开销随语法复杂度和输入大小变化，且数据会受硬件影响，因此请在自己的环境中测量：克隆仓库后，运行 `composer install`，然后运行 `composer bench`。

## 安全防护

正则表达式引擎包含失败记忆化和 ReDoS 防护，因此遇到病态模式时会变慢，而不会卡死。你还可以使用 [`tokenizeMaxLineLength`](https://shikiphp.inline0.dev/zh/docs/options#tokenizemaxlinelength)限制每行的处理量；达到或超过指定长度的行会输出为单个纯文本令牌，以防范恶意构造的单行输入。

## 在生产环境中缓存

确保代码高亮不占用请求处理路径的可靠方法，就是**不要**在每次请求时都运行它。相同代码使用相同选项进行高亮，总会生成相同的 HTML，因此非常适合缓存：

- 对静态网站和文档，在构建时进行高亮。
- 缓存渲染后的 HTML（以代码和选项为键），用于用户提供或存储在数据库中的代码片段，并在源代码变更前重复使用。

在进程中重复使用同一个高亮器（`Shikiphp`门面会为你处理），以便在多次调用间共享语法和主题缓存。
