web-dev-qa-db-ja.com

真の危険なコードパフォーマンス

安全でないコードは、パフォーマンスの高いコードを記述するよりも、Windows APIなどにアクセスして安全でない型のキャストを行う方が適切であることを理解していますが、実際のアプリケーションでそれを使用することでパフォーマンスが大幅に向上したことに気付いたことはありますか?安全なc#コードと比較した場合。

23
Miguel

いくつかのパフォーマンス測定

パフォーマンス上の利点は、思ったほど大きくはありません。

C#で、通常のマネージドアレイアクセスと安全でないポインターのパフォーマンス測定を行いました。


任意のCPUを使用してVisualStudio 2010、.NET4の外部で実行されたビルドの結果|次のPC仕様でビルドをリリースします:x64ベースのPC、1つのクアッドコアプロセッサ。 Intel64ファミリ6モデル23ステッピング10純正Intel〜2833 Mhz

_Linear array access
 00:00:07.1053664 for Normal
 00:00:07.1197401 for Unsafe *(p + i)

Linear array access - with pointer increment
 00:00:07.1174493 for Normal
 00:00:10.0015947 for Unsafe (*p++)

Random array access
 00:00:42.5559436 for Normal
 00:00:40.5632554 for Unsafe

Random array access using Parallel.For(), with 4 processors
 00:00:10.6896303 for Normal
 00:00:10.1858376 for Unsafe
_

安全でない*(p++)イディオムは実際には遅くなることに注意してください。私の推測では、これは、安全なバージョンでループ変数と(コンパイラーが生成した)ポインターアクセスを組み合わせていたコンパイラーの最適化を破りました。

github で入手可能なソースコード。

25
Thomas Bratt

他の投稿で述べられているように、あなたはcan非常に特殊なコンテキストで安全でないコードを使用して、パフォーマンスを大幅に向上させます。それらのシナリオの1つは、値型の配列を反復処理することです。安全でないポインタ演算を使用すると、forループ/インデクサの通常のパターンを使用するよりもはるかに高速になります。

struct Foo
{
    int a = 1;
    int b = 2;
    int c = 0;
}

Foo[] fooArray = new Foo[100000];

fixed (Foo* foo = fooArray)  // foo now points to the first element in the array...
{
    var remaining = fooArray.length;
    while (remaining-- > 0)
    {
        foo->c = foo->a + foo->b;
        foo++;  // foo now points to the next element in the array...
    }
}

ここでの主な利点は、配列インデックスのチェックを完全に排除したことです。

この種のコードは非常にパフォーマンスが高いものの、処理が難しく、非常に危険(安全ではない)である可能性があり、いくつかの基本的なガイドライン(可変構造体)に違反しています。しかし、これが適切なシナリオは確かにあります...

17
MattDavey

良い例は画像操作です。バイトへのポインタを使用してピクセルを変更すると(安全でないコードが必要になります)、かなり高速になります。

例: http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx

そうは言っても、ほとんどのシナリオでは、違いはそれほど目立たないでしょう。したがって、安全でないコードを使用する前に、アプリケーションのプロファイルを作成してパフォーマンスのボトルネックがどこにあるかを確認し、安全でないコードが本当に高速化の解決策であるかどうかをテストしてください。

14
Botz3000

ビデオ操作コードに安全でないコードを使用しています。このようなコードでは、値などの内部チェックなしでできるだけ速く実行する必要があります。安全でない属性がないと、30fpsまたは60fpsのビデオストリームに追いつくことができません。 (使用するカメラによって異なります)。

しかし、速度のために、グラフィックスをコーディングする人々によって広く使用されています。

1
user3800527

これらの答えを見ているすべての人に、答えは優れているにもかかわらず、多くの変化があり、答えが投稿されていることを指摘したいと思います。

.netはかなり変更されており、ベクター、スパン、ReadOnlySpanなどの新しいデータ型や、 Systemにあるようなハードウェア固有のライブラリやクラスにアクセスできるようになっていることに注意してください。コア3.0の.Runtime.Intrinsics

この ブログ の投稿を見て、ハードウェアに最適化されたループの使用方法と、この ブログのフォールバック 最適なハードウェアが利用できない場合の安全な方法。

1
Walter Vehoeven

さて、私はこのブログ投稿を読むことをお勧めします: MSDNブログ:CLRでの配列境界チェックの省略

これにより、C#で境界チェックがどのように行われるかが明確になります。さらに、JITが彼の「保存」ループで境界チェックを削除するので、Thomas Brattsテストは(コードを見ると)役に立たないように見えます。

1
DerPrzem