人生苦短,别用慢终端
摘要
本文详细介绍了通过避免框架、缓存补全以及懒加载工具来加速终端启动的实用技巧,实现了30毫秒的shell启动。
<p><a href="https://lobste.rs/s/k0sbbv/life_is_too_short_for_slow_terminal">评论</a></p>
查看缓存全文
缓存时间: 2026/06/08 03:18
# 生命太短,别让终端拖慢你
Source: https://mijndertstuij.nl/posts/life-is-too-short-for-a-slow-terminal/
我的几乎所有工作都在终端内完成。Git、kubectl、tmux、SSH 登录服务器,几乎全天开着。如此频繁使用的工具必须快。打开新标签页、敲击字符或按 Tab 补全时的任何延迟,我每天都要感受数百次。这是千刀万剐式的折磨。
我的 Shell 启动时间大约 30 毫秒:
```
$ for i in {1..5}; do /usr/bin/time zsh -i -c exit; done
0.03 real 0.02 user 0.01 sys
0.03 real 0.02 user 0.01 sys
...
```
这是一个功能齐全的交互式 shell——包括补全、语法高亮、自动建议、fzf 和 direnv——耗时不到 30fps 的一帧时间。新标签页瞬间打开。这背后从未有过什么大型优化项目;我只是始终保持着 shell 的简洁高效,多年来这成了习惯。以下是我的做法,所有配置均可在[我的 dotfiles](https://github.com/mijndert/dotfiles) 中找到。
## 不要框架
最大的胜利在于**没有**的东西:没有 oh-my-zsh,没有 prezto 或插件管理器。老实说我从未理解这些框架的吸引力。人们安装 oh-my-zsh,带上数百个插件和主题,最终可能只用上其中 5% 的功能,然后每次打开 shell 都要为剩下的 95% 付出时间和计算资源的代价。插件管理器在此基础上还增加了额外开销。
我准确使用三个插件,通过安装脚本一次性 git 克隆,并从 `.zshrc` 中 source:
```zsh
source ~/.zsh/fzf-tab/fzf-tab.plugin.zsh
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
```
没有插件管理器在启动时进行依赖解析,source 一个已在磁盘上的文件几乎是零成本的。
## 缓存补全
`compinit` 是典型 `.zshrc` 中最耗时的部分之一。默认情况下,它会在每次打开 shell 时对所有补全文件进行安全检查。解决方法是仅当缓存(`.zcompdump`)超过 24 小时才执行完整检查,否则用 `-C` 跳过检查:
```zsh
autoload -Uz compinit
if [[ -n ~/.zcompdump(#qNmh-24) ]]; then
compinit -C
else
compinit
fi
```
那个 glob 限定符(`#qNmh-24`)的含义是“存在且在过去 24 小时内被修改过”。因此每天执行一次完整的 `compinit`,其余时间读取缓存。
## 懒加载
nvm 可能是最臭名昭著的 shell 启动杀手;急切地 source 它很容易增加半秒钟。但我并非每个 shell 都需要 nvm,只有在输入 `nvm` 时才需要。所以我将它包装成一个在首次使用时替换自身的函数:
```zsh
export NVM_DIR="$HOME/.nvm"
nvm() {
unset -f nvm
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" --no-use
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"
nvm "$@"
}
```
第一个 `nvm` 调用删除桩函数,source 真正的 nvm(带 `--no-use` 避免解析 node 版本),然后转发参数。
kubectl 补全同理,它们会调用 `kubectl` 二进制来生成补全脚本。我只在第一次实际运行 kubectl 后加载:
```zsh
kubectl() {
command kubectl "$@"
local ret=$?
if [[ -z $KUBECTL_COMPLETE ]]; then
source <(command kubectl completion zsh)
KUBECTL_COMPLETE=1
fi
return $ret
}
```
这个模式适用于很多情况:任何告诉你把 `eval "$(tool init zsh)"` 放在 `.zshrc` 中的东西都是懒加载的候选,因为每个这样的调用都会在启动时分叉进程并评估其输出。我保留了 `direnv` 和 `fzf` 的急切加载,因为它们快且我经常使用。严格审视你真正频繁使用的东西。
## 非阻塞提示符
同步运行 `git status` 的提示符会在任何大小合适的仓库中产生延迟。这种延迟在每次按 Enter 时都会感受到,甚至比启动慢更糟糕。我使用 [pure](https://github.com/sindresorhus/pure),它会立即显示提示符,然后在 git 信息准备好时异步填充。我短暂尝试用 zsh 内置的 `vcs_info` 替代它,但 pure 的异步行为就是……更好。你也可以在自己的提示符中实现异步 git status,但 pure 很好地封装了符合我需求的方案。
## 终端本身
Shell 启动只是故事的一半,因为模拟器增加了自身的输入延迟。我使用 [Ghostty](https://ghostty.org/),它是 GPU 加速的原生终端,配置只有七行。结合 `tmux new -A -s main` 别名(`t`),新终端窗口直接带我回到现有会话。
## 测量自己的 Shell 性能
你不必相信我的话,你可以测量自己终端的时间消耗。有三种延迟需要关注:启动时间、提示符延迟和输入延迟。
运行几次(第一次总是较慢因为冷缓存):
```bash
time zsh -i -c exit
```
我认为 100ms 以下不错,50ms 以下很好。如果看到 500ms 或更多,那你需要做些工作。
为了更准确的统计,使用 [hyperfine](https://github.com/sharkdp/hyperfine):
```bash
hyperfine --warmup 3 'zsh -i -c exit'
```
Zsh 还自带分析器。将以下放在 `.zshrc` 最顶部:
```zsh
zmodload zsh/zprof
```
最底部:
```zsh
zprof
```
打开新 shell 即可获得时间排序表。最顶部的条目通常是 `compinit`、`nvm.sh` 的 source 或一些 `eval "$(...)"`。修复顶部的一项,重新运行,重复。完成后移除这两行。
如果 zprof 不够精细,可以用时间戳追踪整个启动过程:
```bash
zsh -ixc exit 2>&1 | ts -i '%.s' | sort -rn | head -20
```
或者设置 `PS4='+%D{%s.%6.}: '` 并运行 `zsh -ixc exit 2> startup.log`,然后查找行之间的大跳转。
启动可以很快,但每次提示符重绘可能很慢。`cd` 进入你最大的 git 仓库并按 Enter;如果下一个提示符出现前有延迟,那就是你的提示符在同步工作拖慢它。你可以切换到异步提示符,或者干脆去掉 Git 功能。
## 总结
这些优化大多数是关于“不做什么”。是关于有意为之,只添加你真正使用的东西。我每天打开的几十个会话瞬间启动,终端感觉像是大脑的扩展,而不是需要等待的应用程序。对于我整天使用的工具,这是不可妥协的。
以上所有内容都在[我的 dotfiles 仓库](https://github.com/mijndert/dotfiles) 中,如果你想借鉴的话。
相似文章
Linux 终端内存占用
作者调查了 Linux 上 `kitty` 终端的内存占用过高问题,通过基准测试比较了包括 `xterm`、`alacritty`、`gnome-terminal` 和 `konsole` 在内的多种终端的资源消耗。分析表明,与现代化的 GPU 加速替代品相比,`xterm` 和 `st` 等轻量级终端的内存占用显著更低。
@aarondfrancis:也许把终端重写了5次真的值了
开发者反思,反复重写一款终端工具终于带来了回报
@browser_use:不到1秒启动25个浏览器,尽情享受
Browser Use 推出全新浏览器基础设施服务,具备亚秒级冷启动、更低成本(每小时0.02美元)以及无限扩展能力,现已面向开发者上线。
LiteCoder-Terminal:扩展用于学习语言智能体的长程终端环境
LiteCoder-Terminal-Gen 引入了一种零依赖的合成管道,可生成可执行的终端训练环境,并产出 SFT 和 RL 数据集,使语言智能体在 Terminal Bench 基准测试上取得显著的性能提升。
快优于慢
一篇博客文章,主张软件开发中的速度能带来更好的学习和决策,并提供实用建议,如避免拖延和尽早分享工作。