C# の参照型変数が null ポインター( if (x == null)
... など)であるかどうかをテストするパフォーマンスは、整数がゼロより小さいか、bool が false であるかをテストする場合と比較してどのようなものですか?
このようなヌル ポインター テストに関して他にわかっている問題はありますか。
ゲームのすべてのフレームでこれらのテストを何百回も行っていますが、これらが問題を引き起こす可能性があるかどうか、またはより効率的に実装できるかどうか疑問に思っていました。
C# の参照型変数が null ポインター( if (x == null)
... など)であるかどうかをテストするパフォーマンスは、整数がゼロより小さいか、bool が false であるかをテストする場合と比較してどのようなものですか?
このようなヌル ポインター テストに関して他にわかっている問題はありますか。
ゲームのすべてのフレームでこれらのテストを何百回も行っていますが、これらが問題を引き起こす可能性があるかどうか、またはより効率的に実装できるかどうか疑問に思っていました。
無効性テストは、単純な「0 に等しい」テストと同等である可能性があります。それらは非常に非常に安価です - 数百万のフレームレートを持っていない限り、フレームあたりわずか数百はまったく重要ではありません:)
アプリのプロファイリングを行って、実際に時間が費やされている場所を特定する必要があります。推測するよりもはるかに生産的です。理想的には、現在のパフォーマンスを測定するだけでなく、特定の変更によってパフォーマンスが大幅に低下したかどうかを確認できるように、いくつかのベンチマークも作成するようにしてください。
null の値をテストすることは、型チェックなどを必要とする複雑な操作ではなく、関連するメモリ割り当てもありません。
ステートメントif (x == null)
を逆アセンブルすると、次のようになります。
00000030 cmp qword ptr [rsp+20h],0
00000036 jne 000000000000004A
つまり、テストはポインタ値の単純な整数比較として実装されます。
おそらく主観的ですが、nullチェックはゼロに等しいチェックと同等であり、同じくらい迅速です。だから私はあなたがこれについて心配するべきではないと思います。
同様に-パフォーマンスの問題がない限り、なぜわざわざそれで遊んでいるのか。
また、同様に、パフォーマンスの問題がある場合は、いくつかのnullチェックを排除するのではなく、コードの複雑なブランチからパフォーマンスを獲得できる可能性があります。
とは言うものの、条件付きコードの場合、潜在的なパフォーマンスの向上(ただし、真剣にベンチマークする必要があります)は、1つ以上の条件の変更の結果として設定されるロジックのさまざまなブランチにデリゲートを使用することかもしれません-しかし、私はこのようなソリューションが実際に一般的なケースでパフォーマンスを向上させる場合、特に「isnull」シナリオの場合は驚きます。だから、それは私がこのようなものを意味します:
if([condition])
{
Foo();
}
else
{
Bar();
}
たとえば、[condition]
ローカル変数が含まれている_obj
場合(あなたの場合_obj == null
)-次のようなものに置き換えることができます(ただし、スレッドの問題には非常に注意してください)。
private Action _logic;
private object _obj;
public Object Obj {
get { return Obj; }
set {
_obj=value;
if([condition])
_logic = () => Foo();
else
_logic = () => Bar();
}
}
そして今、あなたが以前[condition]
に分岐を行うことをチェックしたどんなコードでも、あなたは今単にするだけです:
_logic();
[condition]
この種のことは、が複雑であり、重要なことに、プロファイリングを通じて多くのプロセッサ時間を費やしていることが証明されている場合に、ほとんどの改善が得られます。デリゲートを使用すると、条件分岐にわずかなオーバーヘッドが発生しますが、そのオーバーヘッドがthenの実行よりも少ない場合[condition]
、特にこれらのチェックが非常に頻繁に実行されている場合は、違いが生じる可能性があります。
これには他にもバリエーションがあります。最も一般的なのは、等価性チェックに基づいてコードのブランチを選択する代わりに、値から派生した関数ルックアップテーブルです(これは、どのように大きなswitch/caseステートメントを実装できるかです-Dictionary
列挙型によってキーに追加されたデリゲート/ valueがチェックされます-これにより、値の複数のチェックが回避されます)。
ただし、最終的には、プロファイリングのデューデリジェンス(もちろん、前後)がなければ、このような最適化を実行することは基本的に無意味です。
あなたのように集中的なチェックを行うと、パフォーマンスが低下する可能性がありますが、これは特定のアプリに対する独自の基準によってのみ測定できます.
テストのポイントに基づいて、何をいつチェックするかをより賢くする方法が他にもある可能性があります。ただし、アプリケーションについて詳しく知らなければ、これに対する答えを導き出すのは非常に困難です。
で問題(パフォーマンスまたはその他)はありませんif (x == null)
。
これは絶対に問題にならないはずです - あなたが言及するすべてのテストは、通常、1 クロック サイクルかかります。条件付き分岐によるパフォーマンスへの影響がある場合、通常は予測不可能な、または少なくとも予測が困難な分岐動作が分岐予測子を汚し、投機的に実行された分岐の中止を必要とすることが原因です。