15

C#/。NET(さらにはJava)での行列の乗算が非常に遅くなる理由がよくわかりません。

このベンチマークを見てください(ソース):更新されたベンチマークを見つけようとしています。

JavaとC#とC++の内訳

C#の整数および倍精度のパフォーマンスは、MSVC++でコンパイルされたC++に非常に近いものです。ダブルの場合は87%、32ビット整数の場合は99%高速です。かなり良いと思います。しかし、次に行列の乗算を見てください。ギャップはC#に広がり、約19%速くなります。これは私には理解できないかなり大きな矛盾です。行列の乗算は、単純な数学の集まりにすぎません。どうしてこんなに遅くなっているの?同等の数の単純な浮動小数点または整数演算とほぼ同じくらい高速であるべきではありませんか?

これは、ゲームやXNAで特に懸念されます。この場合、物理エンジンなどで行列とベクトルのパフォーマンスが重要になります。少し前に、Monoはいくつかの気の利いたベクトルと行列クラスを介してSIMD命令のサポートを追加しました。SIMDを使用したC++ほど高速ではありませんが、ギャップを埋め、Monoを手書きのC++よりも高速にします。(ソース

行列の乗算の比較

何が起きてる?

編集:よく見ると、2番目のグラフを読み間違えました。C#はかなり近いように見えます。最初のベンチマークは、ひどく間違ったことをしているだけですか?申し訳ありませんが、最初のベンチマークのバージョン番号を見逃しました。いつも聞いている「C#線形代数は遅い」の参考資料として手に取った。私は別のものを見つけようとします。

4

4 に答える 4

13

このような大きなマトリックスでは、CPUキャッシュが制限要因になります。非常に重要なのは、マトリックスの保存方法です。そして、ベンチマークコードはリンゴとオレンジを比較しています。C ++コードはジャグ配列を使用し、C#コードは2次元配列を使用します。

ジャグ配列を使用するようにC#コードを書き直すと、速度も2倍になります。配列インデックスの境界チェックを回避するために行列乗算コードを書き直すことは無意味に思えました。実際の問題にこのようなコードを使用する人は誰もいません。

于 2010-07-12T15:41:25.773 に答える
10

XNA行列演算が遅いという考えの起源を説明するには:

まず第一に、初心者レベルの落とし穴があります。XNAMatrixクラスoperator*はいくつかのコピーを作成します。これは、同等のC++コードから予想されるものよりも低速です。

(もちろん、を使用する場合はMatrix.Multiply()、参照で渡すことができます。)

2つ目の理由は、Xbox360のXNAで使用される.NETCompact Frameworkが、ネイティブのC ++ゲームで使用できるVMXハードウェア(SIMD)にアクセスできないことです。

これが、少なくとも遅いと聞き続ける理由です。投稿したベンチマークからわかるように、リンゴとリンゴを比較すると、それほど「遅い」というわけではありません。

于 2010-07-12T16:20:31.843 に答える
7

明らかに、ベンチマークの作成者は、C#のギザギザの配列と多次元配列の違いを理解していませんでした。それは実際に比較するためのリンゴ同士ではありませんでした。多次元配列の代わりにジャグ配列を使用するようにコードを変更して、Javaに似た方法で動作するようにすると、C#コードは2倍高速に実行されます... Javaよりも高速になります(ただし、それはおそらくわずかですが、統計的に重要ではありません)。C#では、配列スロットの検索に余分な作業が必要であり、配列境界チェックを削除できないため、多次元配列の速度は遅くなります...まだ。

多次元配列がジャグ配列よりも遅い理由の詳細な分析については、この質問を参照してください。

配列境界チェックの詳細については、このブログを参照してください。この記事では、行列の乗算に多次元配列を使用しないように特に警告しています。

于 2010-07-12T15:41:35.757 に答える
3

行列の乗算を処理する更新されたベンチマーク(および新しいタスク並列ライブラリを使用するいくつかのベンチマーク)は次のとおりです。

タスク並列ライブラリ(TPL)を使用した並列行列の乗算

この記事ではさまざまな方法について説明し、多次元配列が不適切な選択である理由を説明します。

行列の乗算を行う最も簡単な方法は、ループ内でi、j、kの順序を使用する.NET多次元配列を使用することです。問題は2つあります。まず、i、jk順序付けは多忙な方法でメモリにアクセスし、さまざまな場所のデータを取り込みます。次に、多次元配列を使用しています。はい、.NET多次元配列は便利ですが、非常に低速です。

于 2010-07-12T16:19:52.360 に答える