2012-02-07 5 views
3

長い質問に申し訳ありませんが、Jon Skeetの参考情報がありますので、若干価値があるかもしれません。要するにInterlocked.Read/Interlocked.Exchangeは.NETよりMonoの方がずっと遅いですか?


Interlocked.Read/Interlocked.Exchangeは、.NETフレームワークで実行中よりもモノラルフレームワークで実行しながら、はるかに遅い実行するように見えます。なぜ私は知りたいのですか。長期で

:次に

public interface IThreadSafeDouble 
{ 
    double Value { get; set; } 
} 

public struct LockedThreadSafeDouble : IThreadSafeDouble 
{ 
    private readonly object Locker; 
    private double _Value; 

    public double Value 
    { 
     get { lock (Locker) return _Value; } 
     set { lock (Locker) _Value = value; } 
    } 

    public LockedThreadSafeDouble(object init) 
     : this() 
    { 
     Locker = new object(); 
    } 
} 

私はthis questionにジョンスキートの答えを読んで、私はこれを作った:私は、32ビット・プラットフォームのためのスレッドセーフなダブルを望んでいたので、私は、この構造体を作っ
構造体:

public struct InterlockedThreadSafeDouble : IThreadSafeDouble 
{ 
    private long _Value; 

    public double Value 
    { 
     get { return BitConverter.Int64BitsToDouble(Interlocked.Read(ref _Value)); } 
     set { Interlocked.Exchange(ref _Value, BitConverter.DoubleToInt64Bits(value)); } 
    } 
} 

その後、私はこのテストを書いた:

private static TimeSpan ThreadSafeDoubleTest2(IThreadSafeDouble dbl) 
    { 
     var incrementTarg = 10000000; 
     var sw = new Stopwatch(); 
     sw.Start(); 
     for (var i = 0; i < incrementTarg; i++, dbl.Value++); 
     sw.Stop(); 
     return sw.Elapsed; 
    } 

    private static void ThreadSafeTest() 
    { 
     var interlockedDbl = new InterlockedThreadSafeDouble(); 
     var interlockedTim = ThreadSafeDoubleTest2(interlockedDbl); 

     var lockedDbl = new LockedThreadSafeDouble(true); 
     var lockedTim = ThreadSafeDoubleTest2(lockedDbl); 

     System.Console.WriteLine("Interlocked Time: " + interlockedTim); 
     System.Console.WriteLine("Locked Time:  " + lockedTim); 
    }  

    public static void Main(string[] args) 
    { 
     for (var i = 0; i < 5; i++) 
     { 
      System.Console.WriteLine("Test #" + (i + 1)); 
      ThreadSafeTest(); 
     } 
     System.Console.WriteLine("Done testing."); 
     System.Console.ReadLine(); 
    } 

そして私は、.NETフレームワーク使用して、この結果を得た: .NET Interlocked test results

とMonoフレームワーク使用して、この結果:私は両方のテストを実行してきました Mono Interlocked test results

を同じマシン上で複数回(のWindows XP)結果は一貫しています。私はなぜInterlocked.Read/Interlocked.ExchangeがMonoフレームワークで非常に遅く実行されるように見えるのか不思議です。

更新:

私は次の、より簡単なテストを書いた:

long val = 1; 
var sw = new Stopwatch(); 
sw.Start(); 
for (var i = 0; i < 100000000; i++) { 
    Interlocked.Exchange(ref val, 2); 
    // Interlocked.Read(ref val); 
} 
sw.Stop(); 
System.Console.WriteLine("Time: " + sw.Elapsed); 

.NETフレームワークは一貫ExchangeReadの両方で〜2.5秒を返します。 Monoフレームワークは〜5.1秒を返します。

+1

"このテストは本当に便利ではありません"から始めよう:現在のバージョンのパフォーマンスを比較するために、Windowsでは.Net 4.0 64bit、LinuxではMonoを実行する。 – skolima

+1

インターロックされたメソッドが遅いかどうかは実際にはわかりませんが、インターフェイスのディスパッチもそうです。結論を導き出す前に、できるだけ多くの一般化を取り除くことをお勧めします(つまり、インターロックされたメソッドをループ内に置くだけです)。 –

+0

@RolfBjarneKvinge - 簡単なテストと結果で質問を更新しました。 – ken

答えて

2

描画パフォーマンスの結論はあまり簡単ではありません。最初の例では、長い< - >ダブル変換が重要な要因になる可能性があります。 long型にすべてのダブルスを変更(および変換を削除)することで、これらは、Windowsの32ビットモノに私の時間です:

Test #1 
Interlocked Time: 00:00:01.2548628 
Locked Time:  00:00:01.7281594 
Test #2 
Interlocked Time: 00:00:01.2466018 
Locked Time:  00:00:01.7219013 
Test #3 
Interlocked Time: 00:00:01.2590181 
Locked Time:  00:00:01.7443508 
Test #4 
Interlocked Time: 00:00:01.2575325 
Locked Time:  00:00:01.7309012 
Test #5 
Interlocked Time: 00:00:01.2593490 
Locked Time:  00:00:01.7528010 
Done testing. 

だから、インターロックの実装は、ここでは最大の要因ではなかったです。

しかし、変換なしの2番目の例があります。それはなぜ起こるのですか?私は、答えはループのアンロール、.NET JITコンパイラでうまくいっていると思います。しかし、それはちょうど推測です。実際のシナリオで連動したパフォーマンスを比較したい場合は、少なくとも2つのオプションがあります。

  1. 実生活のシナリオで比較してください。
  2. JITコンパイラによって生成されたマシンコードを比較し、Interlockedの正確な実装を参照してください。

また、上記の実装で保証されるのは、引き裂かないことです。たとえば、2つのスレッドが値をインクリメントしている場合、合計が正しい(つまり、すべてのインクリメントが考慮される)ことを保証しません(通常は必要です)。

関連する問題