2011-12-29 13 views
31

我正在編寫一個程序來說明多線程程序中緩存爭用的影響。我的第一步是創建一個long的數組,並顯示如何修改相鄰的項目會導致爭用。這是該計劃。爲什麼數組的併發修改很慢?

const long maxCount = 500000000; 
const int numThreads = 4; 
const int Multiplier = 1; 
static void DoIt() 
{ 
    long[] c = new long[Multiplier * numThreads]; 
    var threads = new Thread[numThreads]; 

    // Create the threads 
    for (int i = 0; i < numThreads; ++i) 
    { 
     threads[i] = new Thread((s) => 
      { 
       int x = (int)s; 
       while (c[x] > 0) 
       { 
        --c[x]; 
       } 
      }); 
    } 

    // start threads 
    var sw = Stopwatch.StartNew(); 
    for (int i = 0; i < numThreads; ++i) 
    { 
     int z = Multiplier * i; 
     c[z] = maxCount; 
     threads[i].Start(z); 
    } 
    // Wait for 500 ms and then access the counters. 
    // This just proves that the threads are actually updating the counters. 
    Thread.Sleep(500); 
    for (int i = 0; i < numThreads; ++i) 
    { 
     Console.WriteLine(c[Multiplier * i]); 
    } 

    // Wait for threads to stop 
    for (int i = 0; i < numThreads; ++i) 
    { 
     threads[i].Join(); 
    } 
    sw.Stop(); 
    Console.WriteLine(); 
    Console.WriteLine("Elapsed time = {0:N0} ms", sw.ElapsedMilliseconds); 
} 

我跑的Visual Studio 2010,程序在Release模式編譯,.NET 4.0目標, 「任何CPU」,並且沒有附加的調試器(Ctrl + F5鍵)在64位運行時執行。

該程序在我的系統上運行約1700毫秒,使用單線程。有了兩個線程,它需要超過25秒。鑑於差異是緩存爭用,我設置Multipler = 8並再次運行。結果是12秒,所以爭論至少是部分的問題。

增加Multiplier超過8不會提高性能。

爲了比較,similar program that doesn't use an array只需約2200與兩個線程毫秒時的變量是相鄰的。當我分離變量時,兩個線程版本的運行時間與單線程版本相同。

如果問題是數組索引的開銷,你希望它在單線程版本出現。在我看來,修改陣列時會發生某種互斥,但我不知道它是什麼。

看着生成的IL並不是很有啓發性。也沒有看到拆卸。反彙編確實顯示了一些對(我認爲)運行時庫的調用,但我無法進入它們。

我不精通的WinDbg或其他低級別的調試工具,這些天。自從我需要它以來已經很長時間了。所以我很難過。

我唯一的假設現在是運行時代碼中設置「髒」標誌在每次寫入。看起來像這樣的事情是需要的,以便支持拋出異常,如果數組在枚舉時被修改。但我輕易承認,我沒有直接的證據來支持這一假設。

有人可以告訴我是什麼導致了這個大的放緩?

+2

僅供參考陣列不拋出文章,如果他們同時列舉了修改。 (實施將在其權利範圍內,但實際上CLR實施不這樣做。) – 2011-12-29 20:05:46

+0

@Eric:感謝您的信息。這很好。 – 2011-12-29 20:15:52

回答

36

你有錯誤的分享。我寫了一篇關於它here

+0

有趣。出於某種原因,我認爲數組元數據與實際的數組內容分開存儲,而不是與(或非常接近)'array [0]'相鄰。讓我對我的程序進行修改並測試它。 – 2011-12-29 20:06:12

+0

這正是問題所在。我修改了我的程序以訪問'c [Multiplier *(i + 1)]',執行速度與預期一致。謝謝。 – 2011-12-29 20:13:47

+0

@JimMischel不客氣 - 好問題! – 2011-12-29 20:16:29