LoginSignup
34
15

More than 3 years have passed since last update.

最速のZsh プラグインマネージャーを求めて

Last updated at Posted at 2019-02-07

関連記事
- zshの起動が遅いのでなんとかしたい
- zshの起動が遅いのでなんとかしたい 2

TL;DR

速さを求めるならZpluginを使おう

はじめに

普段もっとも良く使うアプリケーションであるシェルにおいて、なにが一番大事だろうか?
見た目?操作性?拡張性?
いや違う,速さ1
特に起動時の速さが重要だ。

たとえば、起動に1秒かかるシェルと0.1秒で起動出来るシェルがあったとする。
1回の起動あたりに900ms差が出る。
1日にシェルを最低100回起動するので2
$$
\frac{0.9 \cdot 100 \cdot 365}{60\cdot60} \simeq 9 \; \text{hours}
$$

なんということだ、1年で9時間も差が出てしまった。
人生を浪費にしないためにも、一刻でも早くシェルの起動を高速化しなければならないことが分かったと思う3

高速化における課題

素のZshの起動は高速だ。
遅くなる原因は設定やプラグインのせいだ。
しかし、あの便利さを経験してしまったら、プラグインなしのカスタマイズされていないZshは流石にたえられない。
そこで、利便性を維持したまま、高速化を行なうために必要なのは以下の2点である。

  1. 必要な設定やプラグインのみ残し、余計な設定の排除
  2. プラグインの読み込み速度の高速化

本稿では2点めの問題を解決するために、既存のプラグインマネージャの起動・読み込み速度について比較した。

プラグインマネージャー

このサイトに載っているのだけでも沢山のマネージャ・フレームワークが存在するので、そのすべて試すのは難しい(てかやりたくない)。
そこで、高速性を謳っていそうなプラグインマネージャにだけに絞って比較した。
今回比較したプラグインマネージャの2/6時点での情報を表にまとめた。
他にも速そうなものがあったら追加する。

プラグインマネージャ star数 最終更新日(master)
zplug 2,873 Jul 4, 2018
zgen 1,004 Oct 21, 2018
antibody 821 Jan 24, 2019
zplugin 259 Feb 4, 2019
zr 51 Jan 30, 2019

測定方法

起動速度を測定するためにhyperfineというベンチマークコマンドを使用した。

hyperfine --max-runs 15 \
  --warmup 3 \
  --export-json result/$1.json \
  "zsh -d -f -l -c 'source plugin.zsh; exit'"

--max-runsが試行回数で、コマンドの実行にかかった時間の平均・標準偏差・最大値・最小値を測ってくれる。
zshの起動はI/Oやプラグインマネージャのキャッシュの影響で初回と2回目以降で速度が変わってしまうので--warmupで実際の測定前に複数回(3回)事前にコマンドを実行しおく。
zsh -d -f -l -c 'source plugin.zsh; exit'で、コンフィグをロードせずにZshを立ち上げ、プラグイン関係のスクリプトをロードしてから終了するまでの時間を計測した。

ちなみに自分はlinux OSで試している。違うOSだと違う結果になるかもしれない。

測定設定

測定する時は読み込むプラグインの数で場合分けした。

  1. プラグイン0個
    1. プラグインマネージャによっては内部でcompinitを行っているものあるので、合わせるためにそれだけは行っておく
  2. 普段使っているプラグイン10個

最初の設定では、プラグインマネージャのオーバーヘッドを測り、2つ目で総合的な速度を測定する。
プラグイン数が少ないない人は前者を、多くのプラグインを使う人は後者を参考にしたらいいと思う。

プラグインマネージャ

実際に測定に使ったスクリプトを載せておく。
自分は各プラグインマネージャについてはチュートリアルを見たぐらいなので、「より高速な方法があるぞ」という場合は教えて欲しい。

zplug

プラグイン0個

source ~/.zplug/init.zsh

if ! zplug check; then
     install
fi

zplug load

プラグイン10個
起動時にはいらないプラグインについては遅延読み込みを行なう。

source ~/.zplug/init.zsh

zplug "zsh-users/zsh-completions"
zplug "zsh-users/zsh-autosuggestions"
zplug "zsh-users/zsh-syntax-highlighting", defer:2, lazy:true
#
zplug "mafredri/zsh-async"
zplug "sindresorhus/pure"

zplug "marzocchi/zsh-notify", if:"has 'terminal-notifier' || has 'notify-send'"

zplug "b4b4r07/enhancd", use:"init.sh", lazy:true
zplug "vintersnow/anyframe", lazy:true
zplug "lukechilds/zsh-nvm", lazy:true, as:command
zplug "greymd/tmux-xpanes", lazy:true, as:command

zplug 'zplug/zplug', hook-build:'zplug --self-manage'

if ! zplug check; then
   zplug install
fi

zplug load

zgen

プラグイン0個

source "${HOME}/.zgen/zgen.zsh"

if ! zgen saved; then
  zgen save
fi

プラグイン10個
遅延読み込みはない?

source "${HOME}/.zgen/zgen.zsh"

if ! zgen saved; then

  zgen load "zsh-users/zsh-completions" src
  zgen load "zsh-users/zsh-autosuggestions"

  zgen load "mafredri/zsh-async"
  zgen load "sindresorhus/pure"

  zgen load "marzocchi/zsh-notify"

  zgen load "vintersnow/anyframe"
  zgen load "b4b4r07/enhancd"
  zgen load "lukechilds/zsh-nvm"
  zgen load "greymd/tmux-xpanes"

  zgen load "zsh-users/zsh-syntax-highlighting"

  zgen save
fi

antibody

antibodyはまず、プラグインのインストールなどをzshrcでは管理せず、コマンドで実行することで読み込みスクリプトを自動生成して(antibody_bundle.zsh)、それをzshrcで読み込む形をとる。
遅延読み込みを行なう方法はない?

プラグイン0個

autoload -Uz compinit; compinit -iCd $HOME/.zcompdump

プラグイン10個

source antibody_bundle.zsh

autoload -Uz compinit; compinit -iCd $HOME/.zcompdump

zplugin

プラグイン0個

### Added by Zplugin's installer
source '/home/vinter/.zplugin/bin/zplugin.zsh'
autoload -Uz _zplugin
(( ${+_comps} )) && _comps[zplugin]=_zplugin
### End of Zplugin's installer chunk

# compinitの代わりが用意されていた
zpcompinit

プラグイン10個
いろいろオプションがあってどうするべきなのかよく分からない。
ここを参考にセットアップ

### Added by Zplugin's installer
source '/home/vinter/.zplugin/bin/zplugin.zsh'
autoload -Uz _zplugin
(( ${+_comps} )) && _comps[zplugin]=_zplugin
### End of Zplugin's installer chunk

zplugin light "zsh-users/zsh-completions"

zplugin ice wait"!0" atload"_zsh_autosuggest_start"
zplugin light "zsh-users/zsh-autosuggestions"

zplugin light "mafredri/zsh-async"
zplugin light "sindresorhus/pure"

zplugin light "marzocchi/zsh-notify"

zplugin ice wait'!0'; zplugin light "vintersnow/anyframe"
zplugin ice wait'!0'; zplugin light "b4b4r07/enhancd"
zplugin ice wait'!0'; zplugin light "lukechilds/zsh-nvm"
zplugin ice wait'!0'; zplugin light "greymd/tmux-xpanes"

zplugin ice wait"!0" atinit"zpcompinit; zpcdreplay"
zplugin light "zsh-users/zsh-syntax-highlighting"

zr

これもantibody同様にロードファイルを作っているだけ

プラグイン0個

autoload -Uz compinit; compinit -iCd $HOME/.zcompdump

プラグイン10個

if [[ ! -f ~/.zr/init.zsh ]]; then
  zr load \
    zsh-users/zsh-completions \
    zsh-users/zsh-autosuggestions \
    zsh-users/zsh-syntax-highlighting \
    mafredri/zsh-async \
    sindresorhus/pure \
    marzocchi/zsh-notify \
    vintersnow/anyframe \
    b4b4r07/enhancd \
    lukechilds/zsh-nvm \
    greymd/tmux-xpanes
fi

source ~/.zr/init.zsh

結果

2019-02-06-230834_909x364_scrot.png

0 pluginの時はantibodyとzrはcompinitをしているだけなので最速だ。zgenやzplugはロード時にいろいろやっているのか遅い。
zpluginは本体をロードしているわりにはほぼオーバーヘッドがない。

一方で10 pluginでは、顕著な差が出た。
zgenはほぼ速度が変わっていないのでかなり優秀なのだが、zplugin、お前0 pluginの時と比べて速くなっていないか(43ms → 32ms)?

zpluginで読み込みを行った時のプロファイルを見ると

num  calls                time                       self            name
-----------------------------------------------------------------------------------
num  calls                time                       self            name
-----------------------------------------------------------------------------------
 1)    1          11.83    11.83   36.78%     11.83    11.83   36.78%  prompt_pure_state_setup
 2)    4          24.34     6.08   75.63%      4.98     1.25   15.48%  -zplg-load-plugin
 3)   10           2.59     0.26    8.05%      2.33     0.23    7.24%  --zplg-shadow-autoload
 4)    5           2.81     0.56    8.75%      2.08     0.42    6.46%  add-zsh-hook
 5)   16          29.36     1.83   91.25%      1.77     0.11    5.51%  zplugin
 6)    2           1.64     0.82    5.09%      1.64     0.82    5.09%  async_init
 7)    4          26.79     6.70   83.25%      1.37     0.34    4.26%  -zplg-load
 8)    1           1.16     1.16    3.62%      1.16     1.16    3.62%  is-at-least
 9)    4           0.60     0.15    1.86%      0.60     0.15    1.86%  -zplg-register-plugin
10)    4           0.53     0.13    1.65%      0.53     0.13    1.65%  -zplg-shadow-off
11)    1          15.21    15.21   47.28%      0.45     0.45    1.41%  prompt_pure_setup

-zplg-load-pluginの呼び出し回数が4回でこれが遅延読み込みをしていないプラグインの読み込みのようだ。そしてzplugin全体で29msしか使用していないので、ほかのと比べてオーバーヘッドがかなり小さい。
結構な時間を喰うcompinitが出てきていのには驚く。これ遅延読み込み出来たんかい!

一応欠点としては、wait iceなどturbo modeを使うにはZsh 5.3以上でないと行けないようだ

おわりに

zpluginを使おう。


感想

zpluginが良いらしいと聞いて比較してみたくて始めたので、かなりzpluginよりの評価になっていると思う。(zpluginだけ書き方を工夫したりしたので)
でも他のプラグインのドキュメントを見る感じ、より高速な読み込みは出来そうにないと思う。
「もっと良い書き方があるよ!」「このプラグインマネージャなんで試してないの?」みたいな指摘を待っている。
zpluginさんのreadmeを見る感じまだまだ設定出来るところがあるのでもう少し調べたい。
ローカルフィアルもZpluginで管理出来るようなので、zshrc全体をZpluginで管理すればかなり高速な起動が出来そうだ。

参考


  1. 個人的見解です。 

  2. 個人差があります。 

  3. 個人的見解です。 

34
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
15