この記事はVim Advent Calendar 2015の6日目の記事です。 前日はdaisuzuさんによるVimのCTRL-X補完についてでした。
さて、この記事ではVimにおけるVim Plug-inについての速度というものをテーマに、あれこれ考察を述べたいと思います。 一般的なソフトウェアの速度についての話から、Vim Plug-inにおける速度は何か、を掘り下げて考えてみることを目的にします。 また話を単純にするため、UnixにおけるCUI Vimの話のみします。
※記載や認識が間違っている箇所がありましたら教えていただけると喜びます。
一般的なソフトウェアにおける速度について
一般的にソフトウェアにおける速度とは、スループットとレイテンシ、応答時間とで語られることが多いと思います。
スループットは、単位時間あたりにソフトウェアが処理可能なデータ量を指します。 具体的な意味についてはWikipedia:スループットを参照していただくことにします。
レイテンシは、ユーザの入力時点からソフトウェアが応答を返し、実際にユーザへと表示されるまでの時間を指します。 こちらも具体的な意味についてはWikipedia:レイテンシを参照してください。
応答時間は、ユーザの入力時点からソフトウェアが応答を返し始めるまでの時間を指します。 こちらも具体的な意味についてはWikipedia:応答時間を参照してください。
Vim Plug-inにおける速度とは
ここでVim Plug-inにおける速度について考えていきます。 Vimはテキストエディタであり、使用する目的はテキストを編集することだと信じています。 また、Vimの目的から言えば、Vim Plug-inの目的とはテキストの編集を補助することだと言えるかもしれません。 きっと。多分。 I HOPE SO.
テキストを編集するという行為においての速度を気にする場面として、大きく以下のパターンに分けられるのではないでしょうか。
- Vimを起動するとき
- 編集作業を行っているとき
- マクロ等でテキストを一括処理しているとき
以下、各パターンそれぞれについて、速度とは何かを考えてみます。
Vimを起動するとき
我々は今端末にいます。
「さあ、編集を始めよう…!」と思い立ち、または必要にかられ、我々は端末に vim path/to/file
と打ち込み、華麗にReturnをえぐります。
…
…
…
さくっと起動しなかったら、嫌ですよね? Vimの起動時における速度とは、単純にReturnをえぐり込んでからVimの画面が表示され、編集を開始できる状態になるまでの時間と考えることができそうです。 つまり、一般的な議論における応答速度にあたると言えそうです。
編集作業を行っているとき
我々は今Vimでの編集を行っています。
ふと天啓が降りてきて、唐突に public static final String RENBAN_KAISHI= 0;
とテキストを打ち込もうとします。
p … u … b … l … c …
1文字打ち込むごとに、ラグがあったら嫌ですよね? 編集作業を行っている際の速度とは、1文字打ち込んでから次の文字を打ち込めるようになるまでの時間と考えることができそうです。 また、文字が打ち込めても画面に反映されていない状態だとどうにもならないので、文字を打ち込み、画面に反映され、次の文字が打ち込めるようになるまで、と考えて問題ないかと思います。 つまり、一般的な議論におけるレイテンシにあたると言えそうです。
マクロ等でテキストを一括処理しているとき
我々は今、巨大なファイルに対して定型処理を行う必要に迫られています。 一度きりしか使わないけどスクリプトを書いて処理するか、それとも血の滲むような努力を前提として手動で行うか…
「そうだ、マクロ使えばいいじゃん」
「そうだ、Vim scriptでやっちゃおう」
天啓を得た我々は、早速取りかかります。 マクロができたので、早速実行をします。
………. (10分後) … 「いつ終わるのか」
Vim scriptができたので、早速実行をします。
………. (10分後) … 「いつ終わるのか」
時間がかかるなら待ちますが、あまり長い時間は待ちたくないですよね? 古の夜間コンパイルなど2015年の今になっては、ぞっとしない話です。 テキストを一括処理する際の速度とは、単純に処理開始から処理終了までの時間と考えることができそうです。 もちろん、ユーザの体感速度を向上させるために非同期で処理するや進捗を表示するといった工夫はできますが、こと速度の議論においては意味を持ちません。 つまり、一般的な議論におけるスループットにあたると言えそうです。
高速なVim Plug-inとは
ここまででVim Plug-inにおける速度とは何か、ということを考えてきました。 結果的に、速度と一口に言っても、その文脈に応じて意味あいや目的とすることが変わってくることがわかってきました。 つまり単に「高速な」Vim Plug-inと言ったときに、その意味するところは大きく違ってきそうです。 高速なVim Plug-inについて考えるときは、そのVim Plug-inがどういった目的のものなのかをよく考える必要がありそうです。
thinca/vim-quickrunを例に速度を考察してみます。 vim-quickrunの目的と、目的に応じた速度とは、
編集中のバッファをカジュアルに実行し、結果を別バッファに表示する
実行を開始してから、別バッファが開くまたは結果がなるべく早く表示されることが重要かと思います。 これは応答速度の概念が適当かと思います。
編集を中断させない
バックグラウンドで動いているプロセスから出力を受け取ってバッファへと書き出す必要性から、定期的にポーリングを行っています。 ポーリング処理を行っている際はどうしてもVimをブロックせざるを得ないため、レイテンシの概念が適当かと思います。
となります。 (間違ってたらゴメンナサイ。) つまり「vim-quickrunを高速にしたい!」と考えた場合、応答速度を求めるのかレイテンシを求めるのかを切り分けた上でアプローチをする必要があります。
まとめ
ここまでで、Vim Plug-inにおける速度とは何か、というテーマで真面目に考えてみました。 Vim Plug-inにおける速度とは、Vim Plug-inの目的によって様々な視点で考えられること、Vim Plug-inの目的に応じた適当なアプローチをすることが重要であることがわかりました。 スループット、レイテンシ、応答時間のいずれが重要なのかを適当に見極め、適当なアプローチを実施することによって世界は高速なVim Plug-inで溢れることを期待してやみません。
付録
ここまでで速度について抽象的な話をしてきましたが、じゃあ実際にどうするのっていう方法論について書いてみます。 あくまでも参考程度に考えていただき、今まで話をしてきたように目的に応じて都度都度適当なアプローチや方法論を探る必要があることは意識してください。
応答時間を向上させるには
応答時間を向上させるためには、大きく以下のアプローチがあるかと思います。
そもそも処理をしない
アルゴリズムの見直しにより処理をなくす、ないし減らすことで応答時間は向上します。 また、キャッシングの導入によっても向上はしますが、キャッシングのメリット/デメリットやその効果を見極めて慎重に導入する必要があります。
処理を遅延させ、必要になった段階で実行する
Shougo/neobundle.vimではLazy Loadingとして実装されているものです。 みなさま馴染みがあるのではないでしょうか。
処理を非同期で行い、必要になった段階で該当処理が終了しているか判定し、終了していなければ待つ
実装が面倒ですが、場合によっては効果があります。 例えばVim起動時に非同期で外部プロセスを走らせておき、特定のFileTypeに変更されたときに外部プロセスの終了を待つなどができます。
スループットを向上させるには
- そもそも処理をしない
- キャッシングの導入
- 処理を非同期で行い、複数の処理を並列で処理する
- 実行速度の速い言語で実装する
レイテンシを向上させるには
- がんばる (力尽きた)(復活したら何か書くかもしれない)