人生苦短,别用慢终端

Lobsters Hottest 工具

摘要

本文详细介绍了通过避免框架、缓存补全以及懒加载工具来加速终端启动的实用技巧,实现了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 终端内存占用

Hacker News Top

作者调查了 Linux 上 `kitty` 终端的内存占用过高问题,通过基准测试比较了包括 `xterm`、`alacritty`、`gnome-terminal` 和 `konsole` 在内的多种终端的资源消耗。分析表明,与现代化的 GPU 加速替代品相比,`xterm` 和 `st` 等轻量级终端的内存占用显著更低。

快优于慢

Lobsters Hottest

一篇博客文章,主张软件开发中的速度能带来更好的学习和决策,并提供实用建议,如避免拖延和尽早分享工作。