test-unitをメンテナンスしている須藤です。最近@tikkssとtest-unitを改良しているので紹介します。テストを並列実行できるように改良しています。
きっかけ
@tikkssはRed Data Toolsに参加しているのですが、red-datasetsのテストが遅いのをどうにかするということに取り組んでいました。いくつかのケースはテスト内容を減らすことで高速化しましたが、その方法で高速化できるものは一通り対応しつくしました。これ以上の高速化はtest-unitでテストを並列実行できるようにするしかないのでは!?という気持ちになったので@tikkssと一緒に取り組み始めました。
週に1回、お昼の30分で一緒に取り組んでいます。最近は毎週水曜日の12:15-12:45に取り組んでいます。私は東京に住んでいて@tikkssは島根に住んでいるので、Jitsi Meetを使ってオンラインで取り組んでいます。取り組んでいる様子はYouTubeでライブ配信しています。アーカイブもしているので、あとから視聴することもできます。
予定
次の3種類の並列実行をサポートする予定です。
Thread
ベース- マルチプロセスベース
Ractor
ベース
現状
実はまだ完成していないのですが、一部動くものはできています。Thread
を使った並列実行機能は動いていて、マルチプロセスやRactor
を使った並列実行機能はまだ動いていません。この間リリースしたtest-unit 3.6.3にThread
を使った並列実行機能は入っているので、興味がある人は--parallel
オプションを使ってみてください。
なお、普通はThread
を使って並列実行してもテストは速くなりません!RubyでThread
を使って速くなるのはIO待ちが多いときです。RubyのThread
は同時にRubyのコードを実行できないからです。IO待ちになると他のThread
に処理が移るのでIOを待っている間も違う処理をできます。待ち時間を有効活用できるのでIO待ちがある場合は速くなるというわけです。
普通はテスト中にIO待ちになることはそんなに多くありません。そのためThread
を使った並列実行機能で速くなることはほぼないんですねぇ。むしろ、オーバーヘッドがある分、微妙に遅くなります。
そんなに速度向上を期待できないのにどうして実装したかというと、練習のためです。まずは一番簡単なThread
ベースで汎用的な並列実行の仕組みを用意して、その上でマルチプロセスベース・Ractor
ベースの仕組みを実装していこうとしています。
今後
Thread
ベースの仕組みが動くようになったので、マルチプロセスベースの実装に着手し始めています。まだ、各プロセス間でどのように通信するかも決まっていません。今後、プロセス間の通信プロトコルや、実行するテストの情報をどうやって共有するか、テスト結果をどう収集するかなどを検討して実装していくことになります。
マルチプロセスベースの仕組みが仕上がったらRactor
ベースの仕組みに着手する予定です。
マルチプロセスベースの仕組みは速くなると思いますが、Ractor
ベースの仕組みは速くなるかどうかはやってみないとわからないなぁと思っています。
また、こまごました使い勝手の部分の作り込みもまだなのでそのあたりも整備していかないといけません。たとえば、各ワーカーにワーカーIDのような情報を渡してあげないといけません。並列実行する場合、各ワーカーが別々のリソース(たとえば、Railsアプリケーションならデータベースとか)を使った方が速度がでます。共有リソースをロックしたりする必要がなくなるからです。ワーカーIDのような情報があると各ワーカーごとに独立したリソースを確保しやすくなります。
まとめ
最近、@tikkssと一緒に取り組んでいるtest-unitの並列実行対応について紹介しました。これまでどうやって設計・実装してきたかが気になる人はアーカイブやtest-unit/test-unit#235に残されている@tikkssのメモを参照してください。一緒に開発したい人はRed Data Toolsのチャットに来てください。