簡體   English   中英

了解VS2010 C#並行分析結果

[英]Understanding VS2010 C# parallel profiling results

我有一個程序有很多獨立的計算,所以我決定並行化它。

我使用Parallel.For / Each。

雙核機器的結果還可以 - 大多數時候CPU利用率約為80%-90%。 但是,使用雙Xeon機器(即8個內核),我只獲得了大約30%-40%的CPU利用率,盡管該程序在並行部分上花費了相當多的時間(有時超過10秒),我看到它使用了與串行部分相比,這些部分中大約有20-30個線程。 每個線程需要1秒以上才能完成,所以我認為它們沒有理由不能並行工作 - 除非存在同步問題。

我使用了VS2010的內置分析器,結果很奇怪。 即使我只在一個地方使用鎖,分析器報告大約85%的程序時間用於同步(也是5-7%睡眠,5-7%執行,低於1%IO)。

鎖定的代碼只是一個緩存(字典)get / add:

bool esn_found;
lock (lock_load_esn)
    esn_found = cache.TryGetValue(st, out esn);
if(!esn_found)
{
    esn = pData.esa_inv_idx.esa[term_idx];
    esn.populate(pData.esa_inv_idx.datafile);
    lock (lock_load_esn)
    {
        if (!cache.ContainsKey(st))
            cache.Add(st, esn);
    }
}

lock_load_esn是Object類的靜態成員。
esn.populate使用單獨的StreamReader為每個線程從文件中讀取。

但是,當我按下同步按鈕以查看導致最大延遲的原因時,我看到探查器報告的是作為功能入口線的線,並且不報告鎖定的部分本身。
它甚至沒有報告包含上述代碼的功能(提醒 - 程序中唯一的鎖定 )作為阻塞配置文件的一部分,噪聲級別為2%。 當噪音水平為0%時,它會報告程序的所有功能,我不明白為什么它們被視為阻塞同步。

所以我的問題是 - 這里發生了什么?
85%的時間花在同步上怎么樣?
如何找出程序中並行部分的實際問題?

謝謝。

更新 :深入研究線程(使用非常有用的可視化工具)后,我發現大部分同步時間都花在等待GC線程完成內存分配上,並且由於通用數據結構調整大小操作需要頻繁的分配。

我將不得不看看如何初始化我的數據結構,以便它們在初始化時分配足夠的內存,可能避免GC線程的這種競爭。

我今天晚些時候會報告結果。

更新 :看起來內存分配確實是問題的原因。 當我在並行執行的類中使用所有詞典和列表的初始容量時,同步問題更小。 我現在只有大約80%的同步時間,CPU利用率達到70%(先前的峰值僅為40%左右)。

我進一步鑽進每個線程,發現現在很多調用GC分配用於分配不屬於大字典的小對象。

我通過為每個線程提供一個預先分配的這類對象池來解決這個問題,我使用它而不是調用“new”函數。

所以我基本上為每個線程實現了一個單獨的內存池,但是以非常粗糙的方式,這非常耗時,實際上並不是很好 - 我仍然需要使用很多新的來初始化這些對象,只有現在我全局執行一次,即使不得不增加池的大小,GC線程上的爭用也會減少。

但這絕對不是我喜歡的解決方案,因為它不容易推廣,我不想寫自己的內存管理器。
有沒有辦法告訴.NET為每個線程分配預定義的內存量,然后從本地池中獲取所有內存分配?

你能減少分配嗎?

我有過幾次類似的經歷,看着糟糕的性能,並發現問題的核心是GC。 但是,在每種情況下,我都發現我在一些內環中意外地耗盡了記憶,不必要地分配了大量的臨時物體。 我會仔細查看代碼,看看是否有可以刪除的分配。 我認為程序“需要”在內循環中大量分配是很少見的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM