it-swarm-ja.com

より動的なディスパッチを使用すると、コンパイル時間を短縮できますか?

Swiftコンパイル時間は本当に遅いので、プロジェクトのコード量が増えます。そのため、その時間を短縮する方法を探していました。1つのアプローチは、finalやstaticなどの言語キーワードを使用することです。この場合、静的および動的ディスパッチを使用して、コンパイラがコードを処理する方法を変更します。

しかし、私が読んだ限りでは、動的ディスパッチを減らすランタイムオーバーヘッドを回避する方が良いです

したがって、私の最初の疑問は、より動的なディスパッチを使用して実行時にできることをすべて実行すると、実行時のオーバーヘッドを犠牲にしてコンパイル時間が短縮されるかどうかです。

私の2番目の疑問は、実行時のオーバーヘッドが非常に悪いことです。オーバーヘッドを減らすためにコンパイル時間を犠牲にすることができますか?

5
Mariano

静的にディスパッチされた関数と動的にディスパッチされた関数のコンパイル時間に目立った違いはありません。動的ディスパッチには実行時に余分なオーバーヘッドがありますが、これは多くの場合目立たないため、測定する必要があります。

インクリメンタルビルドの問題は次のとおりです。ファイルを編集すると、ファイルで宣言されているもののバイナリ互換性が変更される可能性があります。例えば。メソッドの戻り値の型を変更すると、そのメソッドを使用するすべてのコードを再コンパイルする必要があります。したがって、ソースファイルには、誰が誰を使用するかについての依存関係グラフがあります。この依存関係グラフの上部にあるファイルを変更すると、その下にあるすべてのファイルも再コンパイルする必要があり、それらのファイルを使用するすべてのファイルなども再コンパイルする必要があります。これは巨大なカスケードになる可能性があります。

したがって、クイックコンパイルの秘訣は、これらの依存関係を認識し、依存関係を壊すことです。理想的には、依存関係グラフは非常に浅いです。

C++プログラマーはこれをよく知っていますが、どのヘッダーファイルが含まれているかを確認することで、依存関係を非常に正確に追跡できます。ヘッダーファイルを編集するときは、そのヘッダーを使用するすべてのファイルも再コンパイルする必要があります。したがって、ヘッダーファイルには、安定していると思われる一般的な宣言のみが含まれている必要があり、変更される可能性のある実装の詳細は含まれていません。

ここで動的ディスパッチが役立ちます。具体的な実装に直接依存している場合、変更が実装の詳細のみに関するものであっても、その実装が変更されたときに再コンパイルする必要があることを受け入れます。しかし、抽象インターフェースのみに依存している場合は、インターフェースが変更されたときにのみ再コンパイルする必要があります。具体的な実装はインターフェイスから継承し、そのインターフェイスに必要なすべてのメソッドを実装します。したがって、動的ディスパッチを使用して、クライアントをその依存関係から切り離すことができます。

クライアントは、その揮発性の依存関係に結合されています。

+------+    +------------------+
|Client|--->|VolatileDependency|
+------+    +------------------+

クライアントは、安定したインターフェースを介して揮発性の依存関係から切り離されます。

+------+    +---------------+
|Client|--->|StableInterface|
+------+    +---------------+
                     ^
                     |
            +------------------+
            |VolatileDependency|
            +------------------+

コンパイルユニットを分離し、各ファイルを小さくして焦点を絞ることにより、インクリメンタルコンパイルの平均時間を短縮できます。ただし、追加の抽象化を追加すると、プロジェクト全体がより複雑になります。 Swiftの場合、依存関係を宣言するためのクラスごとの明示的なインポートメカニズムがないように見えるため、これには、プログラマーが誤って揮発性の依存関係を使用しないように特別な注意を払う必要があります。

2
amon