2016-05-10 65 views
0

只是爲了好奇,我製作了一個程序來測試InterLocked與.Net鎖定的性能。 事實證明,InterLocked版本比鎖定版本慢得多,有人請指出,如果我錯過了一些細節在這裏。 根據我的理解,聯鎖應該比鎖定表現要好得多。爲什麼InterLocked比鎖定慢?

public class TestB 
    { 
     private static readonly object _objLocker = new object(); 
     private long _shared; 
     public void IncrLocked() 
     { 
      lock (_objLocker) 
      { 
       _shared++; 
      } 
     } 
     public void IncrInterLocked() 
     { 
      Interlocked.Increment(ref _shared); 
     } 
     public long GetValue() 
     { 
      return _shared; 
     } 
    } 
    class TestsCopy 
    { 
     private static TestB _testB = new TestB(); 
     static void Main(string[] args) 
     { 
      int numofthreads = 100; 
      TestInterLocked(numofthreads); 
      TestLocked(numofthreads); 
      Console.ReadLine(); 
     } 
     private static void TestInterLocked(int numofthreads) 
     { 
      Thread[] threads = new Thread[numofthreads]; 
      for (int i = 0; i < numofthreads; i++) 
      { 
       Thread t = new Thread(StartTestInterLocked); 
       threads[i] = t; 
       t.Start(); 
      } 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 
      for (int i = 0; i < threads.Length; i++) 
      { 
       threads[i].Join(); 
      } 
      sw.Stop(); 
      Console.WriteLine($"Interlocked finished in : {sw.ElapsedMilliseconds}, value = {_testB.GetValue()}"); 
     } 

     private static void TestLocked(int numofthreads) 
     { 
      Thread[] threads = new Thread[numofthreads]; 
      for (int i = 0; i < numofthreads; i++) 
      { 
       Thread t = new Thread(StartTestLocked); 
       threads[i] = t; 
       t.Start(); 
      } 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 
      for (int i = 0; i < threads.Length; i++) 
      { 
       threads[i].Join(); 
      } 
      sw.Stop(); 
      Console.WriteLine($"Locked finished in : {sw.ElapsedMilliseconds}, value = {_testB.GetValue()}"); 
     } 

     private static void StartTestInterLocked() 
     { 
      int counter = 10000000; 
      for (int i = 0; i < counter; i++) 
      { 
       _testB.IncrInterLocked(); 
      } 
     } 
     private static void StartTestLocked() 
     { 
      int counter = 10000000; 
      for (int i = 0; i < counter; i++) 
      { 
       _testB.IncrLocked(); 
      } 
     } 

程序的輸出是...

Interlocked finished in : 76909 ms, value = 1000000000 
Locked finished in : 44215 ms, value = 2000000000 
+0

你只測試這裏有很多併發訪問的情況。對於更公平的測試,您還應該測試在沒有併發訪問或正常數量時哪個更快。 – hvd

+4

我認爲你的測量是有缺陷的。在啓動秒錶之前,啓動所有線程。在測量開始之前,許多線程即使不是大部分線程也將完成。 –

回答

3

您的測試是有缺陷的雅各布·奧爾森提到的原因。此外,您的測試還包括在一個班級中調用方法的開銷(對於lock,顯然這對於​​撥打Interlocked.Increment()來說是無法避免的)

您應該啓動所有線程並安排他們在您之後開始工作「已經啓動了秒錶你可以做到這一點,使它們在ManualResetEvent等待

我已經重寫你的測試代碼,像這樣:。

using System; 
using System.Diagnostics; 
using System.Threading; 

namespace Demo 
{ 
    static class Program 
    { 
     private static readonly object _objLocker = new object(); 
     private static long _shared; 
     private static ManualResetEvent _signal = new ManualResetEvent(false); 

     static void Main(string[] args) 
     { 
      int numofthreads = 100; 
      TestInterLocked(numofthreads); 
      TestLocked(numofthreads); 
      Console.ReadLine(); 
     } 

     private static void TestInterLocked(int numofthreads) 
     { 
      Thread[] threads = new Thread[numofthreads]; 
      for (int i = 0; i < numofthreads; i++) 
      { 
       Thread t = new Thread(StartTestInterLocked); 
       threads[i] = t; 
       t.Start(); 
      } 
      Thread.Sleep(5000); // Make sure threads have had time to start. 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 
      _shared = 0; 
      _signal.Set(); 

      for (int i = 0; i < threads.Length; i++) 
      { 
       threads[i].Join(); 
      } 

      sw.Stop(); 
      _signal.Reset(); 
      Console.WriteLine($"Interlocked finished in : {sw.ElapsedMilliseconds}, value = {_shared}"); 
     } 

     private static void TestLocked(int numofthreads) 
     { 
      Thread[] threads = new Thread[numofthreads]; 
      for (int i = 0; i < numofthreads; i++) 
      { 
       Thread t = new Thread(StartTestLocked); 
       threads[i] = t; 
       t.Start(); 
      } 
      Thread.Sleep(5000); // Make sure threads have had time to start. 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 
      _shared = 0; 
      _signal.Set(); 

      for (int i = 0; i < threads.Length; i++) 
      { 
       threads[i].Join(); 
      } 

      sw.Stop(); 
      _signal.Reset(); 
      Console.WriteLine($"Locked finished in : {sw.ElapsedMilliseconds}, value = {_shared}"); 
     } 

     private static void StartTestInterLocked() 
     { 
      _signal.WaitOne(); 
      int counter = 10000000; 
      for (int i = 0; i < counter; i++) 
      { 
       Interlocked.Increment(ref _shared); 
      } 
     } 

     private static void StartTestLocked() 
     { 
      _signal.WaitOne(); 
      int counter = 10000000; 
      for (int i = 0; i < counter; i++) 
      { 
       lock (_objLocker) 
       { 
        _shared++; 
       } 
      } 
     } 
    } 
} 

現在結果已經(從一個發佈版本):

Interlocked finished in : 11339, value = 1000000000 
Locked finished in : 30546, value = 1000000000 

正如你所看到的,Interlocked速度要快得多。

+0

在我的機器上的輸出是互鎖完成在:139614,值= 1000000000 鎖定完成:30432,值= 1000000000 –

+0

我缺少一些優化,爲什麼我的機器上聯鎖如此之慢? –

+0

@Bovi_Khurja你肯定在調試器外運行發佈版本?你有32位或64位操作系統嗎?您是否將可執行文件構建爲x64/AnyCPU? –