multithreading - 多核+ 超線程- 線程如何分佈?

  显示原文与译文双语对照的内容

我正在閱讀一個新的Intel Atom 330的回顧,其中他們指出任務管理器顯示 4內核,兩個物理內核,再加上兩個由超線程模擬的內核。

假設你有一個具有兩個線程的程序。 假設這些是唯一一個在個人電腦上做任何工作的線程,其他的都是空閑的。 操作系統將兩個線程放在同一個內核上的概率是多少? 這對程序吞吐量有巨大的影響。

如果答案是 0%以外的任何東西,除了創建更多的線程之外還有其他的緩解策略?

我希望 Windows,Linux和 Mac OS X 有不同的答案。


使用回答sk隨著谷歌飼料,然後鏈接后,我發現 GetLogicalProcessorInformation Windows 函數。 它提到了"共享資源的邏輯處理器"。 這種資源共享的一個例子是超線程場景。"這意味著 jalf 是正確的,但它不是一個確切的答案。
时间: 原作者:

Linux有相當複雜的線程調度程序,它很容易理解。 它的一些策略包括:

被動 Loadbalancing: 如果一個物理CPU運行多個任務,調度程序將嘗試在第二個物理處理器上運行任何新任務。

活動 Loadbalancing: 如果有 3個任務,2在一個物理cpu上,另一個在第二個物理處理器空閑時,調度將嘗試將一個任務遷移到它。

它試圖保持線程關聯,因為當一個線程遷移到另一個物理處理器時,它必須重新填充所有的緩存級別,導致任務中的一個停滯。

因此,回答你的問題( 至少在Linux上) ;在一個雙核超線程機器上給出 2個線程,每個線程將在它自己的物理內核上運行。

原作者:

一個理智的操作系統會嘗試在自己的核心上安排計算密集型任務,但是當你啟動上下文切換時出現問題。 現代的操作系統有一個傾向於調度內核的趨勢,在調度時沒有工作,但是這會導致並行應用程序從核心到核心公平自由的交換。 對於並行應用,你不希望這樣做,因為你丟失了數據,因為進程可能在它的內核的緩存中使用了數據。 人們使用處理器關聯性來控制這個,但是在Linux上,sched_affinity()的語義在 distros/kernels/vendors, 等之間可以改變很多。

如果你在Linux上,你可以使用攜帶型Linux處理器親和性庫( PLPA ) 。exe來可移植控制處理器。 這就是 OpenMPI內部使用,以確保流程會將自己的核心多核和multisocket系統;他們剛剛剝離模塊作為一個獨立的項目。 OpenMPI在 Los Alamos中使用了許多其他地方,所以這是well-tested代碼。 我不確定在 Windows 下等價的是什麼。

原作者:

我一直在尋找一些答案 Windows 線程調度,和有經驗的信息,我將在這裡對那些將來可能偶然發現這篇文章。

我編寫了一個簡單的C# 程序來啟動兩個線程。 在我的quad四核 Windows 7 box框中,我看到了一些令人吃驚的結果。

當我不強制關聯時,Windows 把兩個線程的工作負載分散到所有四個內核。 有兩行代碼被註釋掉了- 一個是將線程綁定到一個 CPU,一個是一個建議的理想 CPU 。 建議似乎沒有作用,但是設置線程關聯的確導致 Windows 在自己的核心上運行每個線程。

看到最好的結果,使用免費編譯器編譯這個代碼 csc.exe 附帶. NET 框架 4.0客戶機,並與多核機器上運行它。 當處理器關聯線被註釋掉時,任務管理器顯示了橫跨所有四個內核的線程,每一個都在大約 50% 。 通過關聯設置,兩個線程在 100%處用盡兩個內核,另外兩個內核閑置( 這就是我在運行這個測試之前希望看到的) 。

編輯:我最初發現這兩個配置的性能有一些差異。 但是,我無法複製它們,所以我編輯了這篇文章來反映。 我仍然發現線程關聯有趣,因為它不是我所期望的。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

class Program
{
 [DllImport("kernel32")]
 static extern int GetCurrentThreadId();

 static void Main(string[] args)
 {
 Task task1 = Task.Factory.StartNew(() => ThreadFunc(1));
 Task task2 = Task.Factory.StartNew(() => ThreadFunc(2));
 Stopwatch time = Stopwatch.StartNew();
 Task.WaitAll(task1, task2);
 Console.WriteLine(time.Elapsed);
 }

 static void ThreadFunc(int cpu)
 {
 int cur = GetCurrentThreadId();
 var me = Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Where(t => t.Id == cur).Single();
//me.ProcessorAffinity = (IntPtr)cpu;//using this line of code binds a thread to each core
//me.IdealProcessor = cpu;//seems to have no effect

//do some CPU/memory bound work
 List<int> ls = new List<int>();
 ls.Add(10);
 for (int j = 1; j!= 30000; ++j)
 {
 ls.Add((int)ls.Average());
 }
 }
}

原作者:

你可以通過給兩個線程一個處理器關聯來確定它們是否被調度為相同的執行單元。 這可以在 Windows 或者unix中完成,通過 API ( 所以程序可以要求它) 或者通過管理介面( 所以管理員可以設置它) 。 比如 中的你可以使用任務管理器來限制進程可以在哪個邏輯處理器上執行。

否則,調度基本上是隨機的,你可以期望每個邏輯處理器上有 25%個使用。

原作者:

概率本質上是 0%,操作系統不會利用盡可能多的物理內核。 你的操作系統並不愚蠢。它的任務是安排一切,並且它知道它有哪些核心。 如果它看到兩個CPU-intensive線程,它將確保它們在兩個物理內核上運行。

只要稍微闡述一下,對於高性能的東西,一旦進入MPI或者其他嚴重的並行框架,你肯定想控制在每個內核上運行什麼。

操作系統將使best-effort嘗試使用所有內核,但它沒有你所做的長期信息,即"這個線程將運行很長一段時間",或者"我們將有這麼多線程並行執行"。 所以它不能做出完美的決定,這意味著你的線程會被分配給一個新的內核,這意味著你會陷入緩存的缺失和類似的狀態,這將花費一點時間。 在大多數情況下,它都很好,你甚至不會注意到性能差異。 它也與系統的其餘部分很好,如果有的話。 ( 在某人的桌面上,這可能相當重要) 。 在網格與幾千專用cpu的任務,不是特別想玩好了,你只是想使用每個時鐘周期可用)。

所以對於大規模高性能的產品,是的,你需要每個線程停留在一個核心上,固定。 但是對於大多數較小的任務,它並不重要,你可以信任操作系統的調度程序。

原作者:

這是一個非常好和相關的問題。 眾所周知,hyper-threaded內核不是真正的cpu/核心。 相反,它是一個虛擬的cpu/核心( 從現在開始,我將說核心) 。 Windows CPU調度器為 Windows XP,應該能夠區分來自實際內核的超線程( 虛擬) core 。 你可以想象在這個完美的世界中它處理'恰到好處',而不是一個問題。 你會錯的。

自己的優化 Windows 2008 BizTalk伺服器的建議建議禁用超線程。 對我來說,這表明hyper-threaded核心的處理並不完美,有時線程得到一個時間片 hyper-threaded ( 真正核心的一小部分,10%我猜,Microsoft猜測 20 -30 ) 核心和遭受懲罰。

他們建議禁用超線程以提高伺服器效率的文章參考: http://msdn.microsoft.com/en-us/library/cc615012(BTS.10).aspx

這是BIOS更新之後的第二個建議,這就是他們認為它的重要性。 他們說:

來自微軟的

"禁用 hyper-threading BizTalkserver和 SQL Server 電腦

關鍵hyper-threading被關閉 BizTalkserver電腦。 這是一個BIOS設置,通常在BIOS設置的處理器設置中找到。 Hyper-threading使伺服器似乎更多的處理器/處理器核比實際;然而hyper-threaded處理器通常提供 20和 30%之間的一個物理處理器/處理器內核的性能。 當BizTalk伺服器計算調整它的self-tuning演算法的處理器數量時,hyper-threaded處理器會導致這些調整變得歪斜,這不利於總體性能。 "

現在,他們說,這是由於它扔self-tuning演算法,然後繼續提到( 這表明它是一個更大的調度問題,至少對我來說) 爭用問題。 儘管讀,但我認為它是所有的。 當使用單CPU系統時,超線程是一個好主意,但現在只是一個複雜的問題,它會影響這個multi-core世界的性能。

而不是完全禁用超線程,你可以使用等項目流程套索( 免費) 設置默認cpu關鍵進程緊密聯繫,所以,他們的線程不會分配給虛擬 CPU 。

所以。我不認為有人真的知道如何虛擬 CPU Windows cpu調度程序處理,但我認為這是安全的說xp處理它最糟糕的情況下,他們逐漸改善,但它仍然不完美。 事實上,它可能永遠不會是完美的,因為操作系統沒有任何知識的線程是最好穿上這些慢虛擬內核。 這可能就是問題所在,以及為什麼微軟建議在伺服器環境中禁用超線程。

還要記住即使沒有超線程,也有'核心抖動'的問題。 如果你能在一個核心上保持線程,那是一件好事,因為它減少了核心改變懲罰。

我不知道其他的平台,但在英特爾的案例中,他們發布很多信息線程英特爾軟體網路。 他們也有一個免費的新聞稿( 英特爾軟體調度) 你可以通過電子郵件訂閱,並且最近有很多這樣的文章。

原作者:

操作系統將 2活動線程調度到同一個內核的機會是 。線程被綁定到一個特定的核心( 線程關聯) 。

這背後的原因主要是硬體相關:

  • 操作系統( 還有中央處理器) 想要盡可能少地使用電源,這樣它就能盡可能高效地運行任務,以便儘快進入一個低 power-state 。
  • 在同一個內核上運行所有東西會使它的加熱速度更快。 在病理條件下,處理器可能過熱並降低時鐘以降溫。 過高的熱量也會導致CPU風扇旋轉更快的( 思考 筆記本 ) 併產生更多的噪音。
  • 系統實際上從不空閑。 exe和DPCs運行每個 ms ( 在大多數現代操作系統上) 。
  • 從核心跳到核心的線程的性能下降在 99.99 %的工作負載中微不足道。
  • 在所有的現代處理器中,最後一級緩存是共享的,因此交換內核不是那麼糟糕。
  • 對於Multi-socket系統( Numa ),操作系統將從插槽跳到插槽,這樣進程就會保持內存控制器的"靠近"。 在優化此類系統時,這是一個複雜的域( 數十/數百核) 。

順便說一下,操作系統知道CPU拓撲的方式是通過 ACPI - 一個由BIOS提供的介面。

總而言之,所有這些都歸結為系統電源考慮( 電池壽命,電費單,冷卻解決方案的噪音) 。

...