したがって、私はin
パラメーター修飾子が何をするかを理解します(私は考えます)。しかし、それは非常に冗長であるように見えます。
通常、ref
を使用する唯一の理由は、in
によって明示的に禁止されている呼び出し変数を変更することだと思います。したがって、in
参照による受け渡しは、値による受け渡しと論理的に同等と思われます。
何らかのパフォーマンス上の利点はありますか?物事のバックエンド側では、ref
パラメーターは少なくとも変数の物理アドレスをコピーする必要があり、これは一般的なオブジェクト参照と同じサイズでなければならないというのが私の信念でした。
それでは、大きな構造体だけで利点がありますか、それとも他の場所で魅力的なコンパイラの最適化がありますか?後者の場合、なぜeveryパラメーターをin
にしないのですか?
in
は最近C#言語に導入されました。
in
は実際にはref readonly
です。一般的に、in
が役立つユースケースは1つだけです。つまり、大量のreadonly struct
sを処理する高性能アプリです。
あなたが持っていると仮定:
readonly struct VeryLarge
{
public readonly long Value1;
public readonly long Value2;
public long Compute() { }
// etc
}
そして
void Process(in VeryLarge value) { }
その場合、VeryLarge
メソッドでこの構造体を使用するとき(たとえば、value.Compute()
を呼び出すとき)にProcess
構造体は防御コピーを作成せずに参照渡しされます。コンパイラによって保証されます。
読み取り専用でないstruct
をin
修飾子と共に渡すと、コンパイラーは構造体の呼び出し時に防御コピーを作成する上記のProcess
メソッドでメソッドとアクセスプロパティを使用すると、パフォーマンスに悪影響を及ぼします。
本当に良い MSDNブログエントリ がありますので、注意深く読むことをお勧めします。
in
- introducingの歴史的背景を取得したい場合は、C#言語のGitHubリポジトリで discussion を読むことができます。
一般に、ほとんどの開発者は、in
の導入は間違いと見なされる可能性があることに同意します。これはかなりエキゾチックな言語機能であり、高性能のEdgeの場合にのみ有用です。
in
参照による受け渡しは、値による受け渡しと論理的に同等と思われます。
正しい。
何らかのパフォーマンス上の利点はありますか?
はい。
物事のバックエンド側では、
ref
パラメーターは少なくとも変数の物理アドレスをコピーする必要があり、これは通常のオブジェクト参照と同じサイズでなければならないというのが私の信念でした。
オブジェクトへの参照と変数への参照の両方が同じサイズであるという要件がなく、要件のいずれかがサイズであるマシンワードですが、実際には、32ビットマシンでは32ビット、64ビットマシンでは64ビットです。
「物理アドレス」がそれと関係があると思うことは私には不明です。 Windowsでは、物理アドレスではなく、仮想アドレスを使用します。ユーザーモードコード。物理アドレスがC#プログラムで意味があると考えられる状況を想像してみてください。知りたいです。
requirementがなく、あらゆる種類の参照がストレージの仮想アドレスとして実装されます。参照は、CLI仕様の準拠する実装のGCテーブルへの不透明なハンドルにすることができます。
大きな構造体だけで利点はありますか?
大きな構造体を渡すコストの削減は、機能の動機付けシナリオです。
in
はプログラムを実際に高速化する保証はなく、プログラムを低速化する可能性があることに注意してください。 パフォーマンスに関するすべての質問は、経験的調査によって回答する必要があります。 always wins;である最適化はほとんどありません。これは「常に勝つ」最適化ではありません。
他の場所で魅力的なコンパイラの最適化がありますか?
コンパイラとランタイムはpermittedであり、C#仕様の規則に違反しない場合に選択した最適化を行います。私の知る限り、in
パラメーターの最適化はまだ行われていませんが、将来このような最適化が妨げられることはありません。
なぜすべてのパラメーターを入力してはいけないのですか?
さて、in int
パラメーターではなくint
パラメーターを作成したとします。どのような費用がかかりますか?
double
であり、in double
に変更するとします。この場合も、変数を高性能浮動小数点レジスターに登録することはできません。これはパフォーマンスの意味を持つだけでなく、プログラムの動作を変更することもできます! C#は、64ビットより高い精度で浮動小数点演算を行うことが許可されており、通常、浮動小数点を登録できる場合にのみそうします。
これは無料の最適化ではありません。代替と比較してパフォーマンスを測定する必要があります。設計ガイドラインが示唆するように、最初に大きな構造体を作成しないことが最善策です。
がある。 struct
を渡す場合、in
キーワードを使用すると、メソッドがコンテンツを変更するリスクなしに、コンパイラーがポインターのみを渡す必要がある最適化が可能になります。最後は重要です—コピー操作を回避します。大きな構造体では、これは違いの世界を作ることができます。
これは、関数型プログラミングのアプローチのために行われます。主要な原則の1つは、関数に副作用がないことです。つまり、関数はパラメーターの値を変更してはならず、値を返す必要があります。 C#では、値の変更を許可する参照のみによってコピーされることなく、構造体(および値の型)を渡す方法はありませんでした。 Swiftには、メソッドが値を変更し始める限り、構造体(それらのコレクションは構造体BTW)をコピーするハッキングアルゴリズムがあります。 Swiftを使用している人は、すべてコピーのものを認識していません。メモリ効率が良く明示的であるため、これはNice c#機能です。 what's new を見ると、スタック内の構造体と配列の周りでますます多くのことが行われていることがわかります。そして、これらの機能にはinステートメントが必要です。他の回答で言及されている制限はありますが、.netがどこに向かっているのかを理解するのにそれほど重要ではありません。