【Unity】「AssemblyDefinitionを分けるとコンパイルが高速になる」ってホント?検証してみた!

あけましておめでとうございます。バーチャルキャスト開発部のnotargs(のたぐす)です。

Unity 2017.3から、Assemblyを分割するためのAssemblyDefinitionという機能が追加されました。

この機能を使うと、次のような恩恵が受けられます。

  • 更新がないAssemblyはコンパイルされないため、コンパイル時間の短縮に繋がる
  • アセンブリ同士の依存関係を絞り、アーキテクチャを明確にできる
  • internal(同一Assembly内でのみアクセスできるアクセス修飾子)が使える

さて、この機能ですが、コンパイル時間の短縮があまり体感できなかったので、実際にどの程度短縮されているかを調べてみました!

使用したUnityのバージョン

今回の検証にはUnity 2018.4.14f1を使用しています。

コンパイル時間を計測する

コンパイル時間を調べるためにエディタ拡張を作りました。

Assemblyのコンパイル開始/終了を通知するデリゲートCompilationPipeline.assemblyCompilationStartedCompilationPipeline.assemblyCompilationFinishedを使い、アセンブリの更新にかかった時間を計測しています。

ついでにトータルのコンパイル時間とアセンブリのリロードにかかった時間を表示する仕組みも用意しました。

コンパイルの待ち時間に行われていることを可視化できるほか、不要なAssembly同士の依存関係も見つけられるので、開発中も画面端に常に表示しておくと捗ります。

コード全文

検証に利用するプロジェクト

Assembly1Assembly2Assembly3の3つのAssemblyDefinitionを切ったプロジェクトを用意しました。

Auto ReferencedはOnのままで、Assembly3Assembly Definition ReferencesAssembly1Assembly2の両方を追加しています。

図で書くと次のような依存関係となっています。

いろいろ試してみる

AssemblyDefinitionAssetの設定を変えてみる

試しにAssembly1Allow 'unsafe' Codeにチェックを入れて保存してみると、このようなログが出力されました。

同様に、新しいAssemblyDefinitionが追加/削除されたときも、Packageを含めた全てのAssemblyがコンパイルされます。

Assembly1を変更してみる

Assembly1にあるクラスを変更してみると、次のログが出力されました。

Assembly1と、それに依存したAssemblyがコンパイルされていることがわかります。
Assembly1と依存関係のないAssembly2はコンパイルされていません。

Assembly3を変更してみる

Assembly3にあるクラスを変更してみると、次のログが出力されました。

Assembly3の依存先であるAssembly1Assembly2はコンパイルされていません。

Auto Referencedを外してみる

Auto RerencedはAssemblyをAsssembly-CSharp/Assembly-CSharp-Editorに追加するオプションですが、不要なことも多いと思います。
全てのAssemblyのAuto Referencedのチェックを外し、Assembly1のクラスを変更してみました。

次のようなログが出力されます。

Assembly-CSharpAssembly-CSharp-Editorとの依存関係がなくなったため、Assembly1Assembly3のみがコンパイルされていることがわかります。

まとめ

いかがでしたか?
以上の検証から、AssemblyDefinitionを適切に分ければコンパイルは高速化されることがわかりました。

また、コンパイル時間を減らすためには、次の点に気をつければいいことがわかります。

  • 頻繁に変更が発生するAssemblyはできる限り依存元のAssemblyを減らす
  • 不要ならAuto Referencedのチェックを外す

バーチャルキャストのクライアントでは現状191個のAssmblyがあり、フルコンパイルだと28秒ほどかかってしまいますが、このあたりを意識して設定した結果、局所的な変更であれば8秒程度で終わるようになりました。
コンパイル時間を大きく削減できるので、ぜひ意識してみましょう!

【おまけ】その他検証中に気づいたこと

Riderの設定を見直して速度を更に上げる

IDEにRiderを使っている場合、SettingsのLanguage & Features/Unity Engine内にAutomatically refresh assets in Unityという設定項目があります。

こちらはファイルが更新されたとき、自動的にバックグラウンドでUnityのrefresh assetsを行ってくれるオプションですが、オフにすることで、コンパイル前に走るrefresh assetsの待ち時間を大幅に減らせました。
refresh assetsが長いと感じる人はここの設定もあわせて見直してみましょう。

Project内のAssemblyDefinitionを全て検索する

ProjectViewにt:AssemblyDefinitionAssetと入力すると、プロジェクト内の全てのAssemblyDefinitionを検索できます。
Auto Referencedを一括でOffにする時などに便利なので、ぜひ活用してみてください。