問題
~/.zshrcに記述した eval "$(pyenv virtualenv-init -)"
によって、zshのプロンプト表示が遅くなってることに気づきました。
原因と解決方法を調べたのでまとめました。
結論
~/.zshrcに記述するのを
eval "$(pyenv virtualenv-init -)"
↓
eval "$(pyenv virtualenv-init - | sed s/precmd/chpwd/g)"
に変更する
pyenv-virtualenv initとは?
GitHub - pyenv/pyenv-virtualenv: a pyenv plugin to manage virtualenv (a.k.a. python-virtualenv).
カレントディレクトリにある.python-versionの設定に基づいて、python仮想環境を自動的にactivate/deactivateします。
.python-version
ファイルは、pyenv
でローカルのPython バージョンを設定するために、pyenv local
コマンドで作成・削除できます。
原因
展開されるシェルスクリプトの内容を確認します。
$ echo $(pyenv virtualenv-init -)
以下のシェルスクリプトが実行されています。処理内容を見ていきます。
export PATH="/Users/satsuki/.pyenv/plugins/pyenv-virtualenv/shims:${PATH}" export PYENV_VIRTUALENV_INIT=1 _pyenv_virtualenv_hook() { local ret=$? if [ -n "${VIRTUAL_ENV-}" ]; then eval "$(pyenv sh-activate --quiet || pyenv sh-deactivate --quiet || true)" || true else eval "$(pyenv sh-activate --quiet || true)" || true fi return $ret } typeset -g -a precmd_functions if [[ -z $precmd_functions[(r)_pyenv_virtualenv_hook] ]]; then precmd_functions=(_pyenv_virtualenv_hook $precmd_functions) fi
_pyenv_virtualenv_hook
という関数が定義されています。この関数では以下の処理が実行されます。
- 仮想環境が存在する場合、環境をactivateし、失敗した場合deactiveを行う
- 仮想環境が存在しない場合、環境をactivateする
zshでは precmd_functions
というグローバルな配列で、プロンプトが変更された時に実行する関数を管理しています。
作成した_pyenv_virtualenv_hook
関数を precmd_functions
配列に追加しています。
これにより、プロンプトが変更されるたびにvirtualenvの仮想環境のactivateが実行され、zshの動作が重くなります。
解決方法
pyenv-virtualenvのGitHub Issueでシェル動作が遅くなる現象のDiscussionがあり、回避方法が提案されています。
eval "$(pyenv virtualenv-init)”
の代わりに以下を ~/.zshrcに書き込みます
eval "$(pyenv virtualenv-init - | sed s/precmd/chpwd/g)"
上記のコマンドでは、先ほどのpyenv virtualenv-init
で展開されるシェルスクリプト内のprecmdの文字列をchpwdに書き換えています。
chpwd_functions
というグローバルな配列で、カレントディレクトリが変更された時に実行する関数を管理しています。
よって、プロンプトを変更する度に仮想環境をactivateしていた処理を、カレントディレクトリを変更する度に実行するよう変更しています。
プロンプト表示速度の変化
zsh-prompt-benchmarkでzshのプロンプトレンダリング速度を測ってみました。
修正前
******************************************************************** Prompt Benchmark Results ******************************************************************** Warmup duration 8s Benchmark duration 2.050s Benchmarked prompts 7 Time per prompt 292.84ms <-- prompt latency (lower is better) ********************************************************************
修正後
******************************************************************** Prompt Benchmark Results ******************************************************************** Warmup duration 8s Benchmark duration 2.015s Benchmarked prompts 78 Time per prompt 25.84ms <-- prompt latency (lower is better) ********************************************************************
プロンプト表示速度が大きく改善しました。