簡體   English   中英

在並行計算機上啟動應用程序時的性能問題

[英]Performances issues when launching an application on a parallel machine

我有一個非常奇怪的問題:

我有一個可以並行啟動一些工作程序的應用程序:

for (it = jobList.begin(); it != jobList.end(); it++) {
    DWORD threadId;
    Job job = *it;
    Worker *worker = new Worker(job);
    workers[i] = worker;
    threads[i++] = CreateThread((LPSECURITY_ATTRIBUTES)NULL, (DWORD)0, &launchThread, worker, (DWORD)0, &threadId);
}
WaitForMultipleObjects((DWORD)jobList.size(), threads, (BOOL)true, (DWORD)INFINITE);

它們分配了很多東西,因此我假設它們在新對象上進行同步,但這是它們最終彼此同步的唯一地方。

當我在單核計算機上運行該應用程序時,一切都很好。 當我在多核計算機上啟動應用程序時,性能會變得更差 ,甚至更差:

for (it = jobList.begin(); it != jobList.end(); it++) {
    DWORD threadId;
    Job job = *it;
    Worker *worker = new Worker(job);
    workers[i] = worker;
    threads[i++] = CreateThread((LPSECURITY_ATTRIBUTES)NULL, (DWORD)0, &launchThread, worker, (DWORD)0, &threadId);
    WaitForSingleObject(threads[i-1], (DWORD)INFINITE);
}

有人有合理的猜測要給我嗎?

編輯

我進行了一些測試,發現:

  1. 使用並行分配器的最新狀態更改分配器無濟於事
  2. 與具有雙xeon(具有不同緩存的兩個處理器)相比,在具有Core 2 duo(兩個具有共享L2緩存的內核)的計算機上,多線程應用程序的結果更好。

我以為我手中的應用程序存在內存訪問瓶頸,但是...如何檢查這是否確實是問題所在,還是我應該去看看其他地方?

您個人的Jobnew嗎? new幾乎總是線程安全的,但是通常這種安全會帶來巨大的性能損失 (是的,該論文談論malloc ,但是(1)困擾new的相同問題,以及(2) new通常是使用malloc實現的)。

如果對new Worker(job)的調用失敗,則沒有清除代碼,則可能存在內存泄漏。 當然,您可能已刪除該代碼以發布示例,或者這可能是整個程序,並且您依賴操作系統進行清理。 您可以考慮使用類似於Scope Guard的解決方案。

總的來說,我建議您看一下諸如Intel的Threading Building Blocks或Windows的thread pool之類的東西 那些應該處理許多其他棘手的細節(創建多少線程,如何公平調度,為它們提供什么數據以避免高速緩存未命中,等等)。

當尋求同步時,互鎖*功能有時會被忽略。 它們的速度非常快,但是它們確實會強制進行一些同步和CPU緩存更新,這會使您的速度降低。 有了這樣說,人們可能不得不使用這些功能很多讓你描述的影響。

沒有更多細節,我建議對工作線程進行概要分析,深入研究代碼的冗長部分,並最終確定瓶頸。 由於效果顯着,因此瓶頸應該很明顯。 如果您找到了地點,但沒有找到原因,請使用引起問題的代碼的實際部分來更新您的問題。

您可以嘗試在創建任何工作程序線程之前放入所有動態內存分配。 動態內存分配訪問需要關鍵節訪問的堆。 當前將執行哪些新分配。 當您有多個線程在運行時,這些線程將獲得大量執行時間,並且如果這些工作線程正在對內存進行一些動態分配,那么您的主線程可能會花一點時間分配動態內存,因為它必須等待其他線程的出現。

您要創建多少個線程,您有多少個內核? 每個內核多於2個線程將大大降低性能。

通常,在遇到諸如此類的問題時,您需要設置一個線程池(例如,雙核計算機的最大線程數為4個),然后為每個線程分配一個“作業”。 該作業完成后,您將從作業列表中彈出下一個作業,線程繼續處理新作業。 您執行此操作,直到處理完所有作業。 請記住,池中的線程可以直接從作業列表中獲取下一個作業,而不是讓工作線程將下一個作業分配給它。

工作流程如下。

1)主線程創建許多工作線程。
2)主線程填充作業列表。
3)Worker線程檢查是否還有其他作業,然后從列表中獲取下一個。
4)如果還有作業,請轉到3。
5)完成(或根據您的要求返回2)。

還有其他方法可以解決此問題,但以上方法可能是最有效且最容易實現的方法。

暫無
暫無

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

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