PHPStan がめちゃくちゃ遅い場合
最近、WSL 2 上で PHPStan がめちゃくちゃ遅くて困っていたのですが、 なんとか重い腰を上げて調査をし、高速化する方法を見つけたのでここにメモしておきます。 というかこの方法は、高速化する方法というよりは、遅くならない方法と言った方が正しいのかもしれません。 ググっても出てこなかったのでレアケースなのかもしれませんが、PHPStan が遅くて遅くて困っている方は参考にしてみてください。
現象と原因
現象としては、WSL 2 上で PHPStan を動かすと、処理時間が数分以上かかってしまい WSL 2 がフリーズ状態になってしまうというものです。 VS Code で WSL 拡張機能を使用して接続している場合、PHPStan の実行が遅すぎるために、VS Code と WSL 2 との間の接続が切れてしまいます。 待ってれば返ってくるのなら良いのですが、最悪のパターンだと WSL 2 を強制的に再起動させないといけなくなってしまいます。
原因
いろいろと調査した結果、どうやら PHPStan がマルチスレッドで動作していることが原因と判明。 そういえば以前はこんなに遅くなかったはずで、遅くなったのは PHPStan がバージョンアップしてからだなと思い出しました。 最新の PHPStan ではマルチスレッドによる並列処理はデフォルトで有効になっています。 CPU のコアがたくさんあるような高スペックなマシンであれば、 マルチスレッドで処理速度が早くなるのかもしれませんが、 低スペックなマシンの場合は、各スレッドが CPU やメモリなどのマシンリソースを奪い合ってしまい、 どのスレッドも処理を完了させることができなくなってしまって逆に遅くなってしまうのです。
動いてはいるが遅すぎてほぼほぼフリーズ状態になっているように見えると言った方が正しい感じでしょうか。 PHPStan がマシンリソースを大量に使用してしまうために、 PHPStan 以外の他のプロセスもリソースが足りなくなってしまい、 その結果、何もできない状況に陥ってしまって、WSL 2 の再起動が必要になってしまうと。
マルチスレッドによる並列処理が早いのは、高スペックなマシンで CPU やメモリなどのリソースに余裕がある場合のみです。 低スペックなマシンでリソースが貧弱な状況であれば、シングルスレッドで直列処理した方が早いのです。 なんでもかんでも並列処理にすれば良いってものじゃないってことですね。
解決方法
ということで原因はマルチスレッドで並列処理されていることなので、 マルチスレッドを無効化してシングルスレッド化して直列処理させます。 なお、高スペックのマシンであればデフォルトのマルチスレッドの状態の方が早いかもしれませんので注意してください。 低スペックのマシンであれば、おそらくシングルスレッドの方が早いです。 ご自身の環境に合わせて設定しましょう。 マルチスレッドを無効化してシングルスレッドにすれば、少なくともリソース不足でフリーズすることはなくなります。
マルチスレッドを無効化する方法は主に2つあります。
--debug オプションを使用する
1つ目の方法は PHPStan の実行時に --debug
オプションを使用する方法です。
--debug
オプションを使用すると、下記のような影響があります。
- マルチスレッドが無効になる
- キャッシュが効かなくなる
- プログレスバーの代わりに処理中のファイルの一覧が表示される
- 最初のエラーで処理が停止する
--debug
オプションを使用すると、マルチスレッドを無効化することができますが、
副作用としてキャッシュが効かなくなりますので、後述の2つ目の方法を使用した方が良いでしょう。
どのファイルが処理されているか確認したい場合や、動作確認をしたい場合は、こちらの方法の方が便利かもしれません。
phpstan analyse --debug
設定ファイルで指定する
2つ目の方法は、PHPStan の設定ファイル phpstan.neon で parallel
の maximumNumberOfProcesses
を設定する方法です。
値を 1 に設定するとマルチスレッドが無効になります。
こちらの方法であれば、キャッシュを有効なままにしておけるのでオススメです。
parameters: parallel: maximumNumberOfProcesses: 1