我创建了一个简单的.NET控制台应用程序,在其中我启动了3个托管线程。每个线程执行以下循环:
while (true)
{
System.Console.WriteLine(thread.Name + " " + DateTime.Now);
Thread.Sleep(10);
}
我将第一个线程的优先级设置为高,让应用程序运行几分钟。总的来说,我希望第一个线程更频繁地写入控制台。事实上,它没有明显的效果。将一个线程的优先级设置为高似乎与将所有三个设置保持正常相同。
我在这里错过了什么线程优先级可以解释这个?
答案 0 :(得分:7)
请尝试使用Sleep(1)
。 10ms在线程时间是永恒的,但是Sleep(1)
基本上说“我将剩余的时间切片用于执行到另一个线程”,我认为这就是你想要的。线程优先级不只是使线程更频繁地执行,它只是说“如果调度程序在给予线程A时间片和线程B时间片之间做出选择,则将其提供给具有更高优先级的线程。”尝试这个改变,看看会发生什么。或者,让每个线程执行不同的时间(不要使用睡眠,在一个循环中打印100个元素,在另一个上打印1000,等等)
编辑:更改为睡眠(1),不确定为何被修改。请参阅下面的评论,了解为什么Sleep(1)在这里是更好的选择。
答案 1 :(得分:3)
如果所有三个线程的打印时间不到10毫秒,那么您将看不到输出的任何影响。尝试提出一项需要花费很长时间才能计算出平方根高达一百万的任务,然后看看谁经常运行。
答案 2 :(得分:1)
如果丢失Thread.Sleep
语句,您可能会从优先级较高的线程中看到更多操作。 Thread.Sleep
让其他线程有足够的时间来做他们的事情。
答案 3 :(得分:1)
ThreadPriority可能没有按预期运行......一些关于线程优先级的阅读材料......
线程优先级是邪恶的 http://www.codinghorror.com/blog/archives/000671.html
ThreadPriority.BelowNormal
http://odetocode.com/Blogs/scott/archive/2006/08/27/6053.aspx
为什么睡眠(1)优于睡眠(0)
http://www.bluebytesoftware.com/blog/PermaLink,guid,1c013d42-c983-4102-9233-ca54b8f3d1a1.aspx
答案 4 :(得分:1)
您没有看到任何差异,因为您可能正在多处理器计算机上运行此程序,其中线程不必相互竞争以在单个核心上进行调度。
当高优先级线程正在执行时,调度程序仍然可以将低优先级线程安排到其他内核,因此您没有看到任何显着差异。
如果您想要注意到显着差异,则必须强制线程针对单个核心竞争时间片,其中一次只能执行一个线程。要实现这一点,您应该将所有线程的处理器关联性设置为同一个核心。
我不确定如何在.NET中执行此操作,但在C中您应该使用SetThreadAffinityMask
函数:
HANDLE hThreadLow = CreateThread(NULL, 0, ThreadProc1,
NULL, CREATE_SUSPENDED, &dwThreadLowId);
HANDLE hThreadHigh = CreateThread(NULL, 0, ThreadProc2,
NULL, CREATE_SUSPENDED, &dwThreadHighId);
SetThreadPriority(hThreadLow, THREAD_PRIORITY_BELOW_NORMAL);
SetThreadPriority(hThreadHigh, THREAD_PRIORITY_ABOVE_NORMAL);
SetThreadAffinityMask(hThreadHigh, 0x00000001);
SetThreadAffinityMask(hThreadLow, 0x00000001);
ResumeThread(hThreadLow);
ResumeThread(hThreadHigh);
现在你会发现两个线程之间存在显着差异。在两个线程的每个线程中实现一个计数器,并查看计数值中的差异范围为100x - 10000x。
答案 5 :(得分:1)
灵感来自@Karim Agha' answer here
我认为这是因为多核CPU
使用一个简单的程序来证明这一点,设置两个线程在第一个CPU核心上运行:
process.ProcessorAffinity = (IntPtr) 0x0001;
// 0x0001 = 0000 0001 - run on 1st core
// 0x0002 = 0000 0010 - run on 2nd core
// 0x0003 = 0000 0011 - run on 1st and 2nd core
// 0x0004 = 0000 0100 - run on 3rd core
// and so on
而且,在运行一段时间后,我会得到类似highCount:5179 & lowCount:167
之类的东西。如果我对该行进行评论,它将类似于highCount:3350 & lowCount:3382
。
进一步的证据来自Task Manager
,打开它并使用Set affinity
设置,你会看到立即效果应用于两个线程。
using System;
using System.Diagnostics;
using System.Threading;
namespace Test
{
class Program
{
private static int highCount, lowCount;
private static readonly ManualResetEventSlim Signal = new ManualResetEventSlim(false);
public static void Main()
{
using (var process = Process.GetCurrentProcess())
{
process.PriorityClass = ProcessPriorityClass.High;
// only run on core number 1
process.ProcessorAffinity = (IntPtr) 0x0001;
}
var slowThread = new Thread(() =>
{
while (true)
{
if (Signal.IsSet)
{
break;
}
Console.WriteLine("Lowest");
lowCount++;
}
})
{
Name = "Lowest",
Priority = ThreadPriority.Lowest
};
var fastThread = new Thread(() =>
{
while (true)
{
if (Signal.IsSet)
{
break;
}
Console.WriteLine("Highest");
highCount++;
}
})
{
Name = "Highest",
Priority = ThreadPriority.Highest
};
fastThread.Start();
slowThread.Start();
Console.ReadKey();
Signal.Set();
fastThread.Join();
slowThread.Join();
Console.WriteLine($"highCount:{highCount} & lowCount:{lowCount}");
Console.ReadKey();
}
}
}
答案 6 :(得分:0)
线程不会更频繁地写入控制台,因为它们都在写入之间等待10ms。但是,高优先级线程应该更频繁地写入控制台 ,即写入之间接近真正的10ms。这是因为,虽然优先级较低的线程可以被PC上的其他任务推到一边,但优先级较高的线程在被允许写入之前必须等待更少。
这会回答你的问题吗?