2009-06-23 10 views
20

さまざまなプラットフォームでintおよびlongの場合、より速くまたは遅いですか?Interlocked.Incrementの性能

+0

他の人が指摘するように、それは同じことではありません。それはhttp://msdn.microsoft.com/en-us/magazine/cc163726.aspxによると、Interlocked.Incrementは14nS(または約1秒あたり約7000分の1)かかるので、私はあまり心配しませんパフォーマンスについて – smirkingman

+0

Interlocked.Incrementはスレッド環境で使用することを意図しています – EProgrammerNotFound

答えて

37

アクションが原子的に強制され、メモリバリアとして機能し、メモリの並べ替えの機能を排除します命令の回りにアクセスする。

スレッド間で共有できるアクションをアトミックオン状態にするには、Interlocked.Incrementを使用する必要があります。これは、x ++を完全に置き換えるものではありません。

3

レジスタを更新するだけでCPUバスロックを実行する必要があるため、常に遅くなります。しかし、現代のCPUはレジスタの性能に近づくため、リアルタイム処理でも無視できます。

+3

X86 CPUはInterlockedオペレーション中にBuslockを実行しますが、Interlockedオペレーションを提供するすべてのCPUではBuslockは必要ありません。いくつかのCPUは、単一のキャッシュラインを予約し、バスブロックなしでそのキャッシュライン上でインターロック動作を実行できることを信号で伝えることができます。 – Adisak

4

遅いです。しかし、スカラー変数に対するスレッドの安全性を達成するために私が知っている最も一般的な一般的な方法です。

+1

'volatile'はスカラー上でより優れていますが、うまく使用するには良いコーディング方法が必要であるという欠点があります。 – Abel

+2

揮発性で注意してください。いくつかのプロセッサアーキテクチャ(x86/x64)は、そのメモリがコンパイラに対して揮発性とマークされているかどうかにかかわらず、メモリへのアクセスを並べ替えることができます。 –

6

すぐに考えてみてください。Incrementの呼び出しは、インクリメント演算子の単純なアプリケーションより速くはできません。その場合、インクリメント演算子のコンパイラの実装は内部でIncrementを呼び出し、同じことを実行します。

しかし、あなた自身でテストしても分かるように、同じことはしません。

2つのオプションは目的が異なります。増分演算子は一般的に使用してください。演算をアトミックにする必要がある場合はIncrementを使用し、その変数の他のすべてのユーザーもインターロック操作を使用していることを確認してください。 (それらがすべて協力しているわけではない場合は、実際には役に立ちません)

+0

いいえ、そうではありません - Interlocked.Incrementはプロパティで呼び出すことはできませんが、++演算子は呼び出すことができません。したがって、++はそれを呼び出すことができません。 – SLaks

+0

より正確に言えば、Incrementはref int(またはlong)をとります。 ++は非ref int(またはlong)をとります – SLaks

+3

コンパイラはインクリメントで++を実装できます。単純な "call"命令では実装されませんが、コンパイラによって導入された一時的な命令を使用して実行できます。要点は、コンパイラが空き領域を利用して数値をインクリメントするという方法です。より高速なものがあれば、コンパイラは代わりにそれを使用していました。 –

12

私たちの経験では、Windows上のInterlockedIncrement()などは非常に大きな影響を与えています。あるサンプル事例では、インターロックをなくし、代わりに++/- を使用することができました。これにより、実行時間が140秒から110秒に短縮されました。私の分析では、インターロックがメモリ往復を強制する(そうでなければ、他のコアがどのようにそれを見ることができるか)。 L1キャッシュの読み取り/書き込みは約10クロックサイクルですが、メモリの読み書きは100ほどです。

このサンプルのケースでは、約10億回の増分/減算操作の回数を予測しました。したがって、2Ghz CPUの場合、++/- の場合は5秒、インターロックの場合は50秒です。その差をいくつかのスレッドに広げ、その差を30秒に近づけます。

+5

Micrsoft氏:InterlockedIncrementは、http://msdn.microsoft.com/en-us/library/windows/desktop/ee418650(v=vs.85).aspxで36-90サイクルかかると測定されました。 – Lothar

+1

疑問の余地なく操作、私はコアi7の重い争いの操作の約120回を測定しているが、多分私はそれをボットした? L1キャッシュの読み書きは約10クロックサイクルです... " - そのページを変更してマークし、L1からメモリにフラッシュするだけで十分です別のコアがそれを見る必要がある場合、コンプライアンスのない操作は、100 +ではなくスペクトルの10の端(36に近い)に近いことがあります。 –

4

私もパフォーマンステスト:

揮発性:65174400

ロック:連動62428600

:113248900

TimeSpan span = TimeSpan.FromSeconds(5); 

object syncRoot = new object(); 
long test = long.MinValue; 

Do(span, "volatile",() => { 

    long r = Thread.VolatileRead(ref test); 

    r++; 

    Thread.VolatileWrite(ref test, r); 
}); 

Do(span, "lock",() => 
{ 
    lock (syncRoot) 
    { 
     test++; 
    } 
}); 

Do(span, "interlocked",() => 
{ 
    Interlocked.Increment(ref test); 
}); 
+2

「Do」とは何ですか? – SLaks

+0

時間が経過するまでn回メソッドを実行します – MastsrOfDesaster

+3

だから、もっと待ち時間が増えますか?あなたのメトリックは何ですか? –