我在C#中有一个方法,我希望在一个4核计算机上的控制台应用程序中,从多个线程运行20次。我面临的问题是结果不是我所期望的。当我按顺序运行25次方法时,所用时间为X,我可以在perfmon中看到最大CPU为100%(它告诉我它使用的是1个核心)。使用多个线程运行相同的方法,我希望执行时间为X / 4,并且我期望perfmon中的最大CPU使用率为400%(因为它是一个4核机器)。但是,我只能看到执行时间是X / 2,最大CPU使用率从未超过275%。我尝试了各种各样的东西,比如创建我自己的线程,使用threasdpool等,似乎什么都没有用。有人可以解释/帮助我更好地理解它吗?
其他有趣的事情是,如果我使用Thread.SpinWait(x)
用虚拟任务替换我的方法,执行时间是X / 4,我可以看到最大CPU达到400%。这告诉我,我的方法出了问题,我不明白它是什么。在我的方法中,我没有锁/睡觉。以下是我用来执行的代码:
public static void DoWorkParallel()
{
var s = new List<string> { "a", "b", "c", "d", "e", etc. };
s.ParallelForEach2(x =>
{
MyTask(x);
});
}
public static void DoWorkSequential()
{
var s = new List<string> { "a", "b", "c", "d", "e", etc. };
foreach (var ss in s)
{
MyTask(x);
}
}
public static void ParallelForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
var results = collection.Skip(1).Select(item => new
{
action,
res = action.BeginInvoke(item, null, null)
}).ToArray();
action(collection.First()); /* let the mainthread do a job too*/
foreach (var r in results)
{
r.action.EndInvoke(r.res); /*then wait the rest of time */
}
}
答案 0 :(得分:1)
Thread.SpinWait
正在紧密循环中运行,不执行I / O并且不访问任何内存 - 它没有做任何有用的工作,因此将CPU使用率与任务的CPU使用率进行比较是一个谬误。
如果没有您的任务正在进行的操作的详细信息(无论是访问文件,还是等待互斥锁等),都很难确定发生了什么。
您可以做的一件事是在您的任务中添加Stopwatch
实例,并使用它来打印每次调用所用的时间。将运行任务的结果与DoWorkSequential
和ParallelForEach
进行比较 - 无论方法如何,每次调用都应花费相同的时间。如果ParallelForEach
运行的任务花费的时间更长,则可能表示您有一个互斥的互斥锁,需要用另一种锁定方法替换。
答案 1 :(得分:0)
您可能希望在Parallel.Foreach调用的ParallelOptions参数中将MaxDegreeOfParallelism设置为4。如果不这样做,dotnet4会使用很多工作线程;他们的管理和同步开销可能有点浪费。我有类似的问题,这对我有用。
http://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.aspx
另外,在这里保持简单。请记住,当您使用严格的并行性时,您每秒的记录(cpu核心吞吐量)与每季度的记录(程序员生产率)进行折衷。