多线程任务不使用CPU?

时间:2011-07-04 10:37:37

标签: c# .net

我在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 */
    }
}

2 个答案:

答案 0 :(得分:1)

Thread.SpinWait正在紧密循环中运行,不执行I / O并且不访问任何内存 - 它没有做任何有用的工作,因此将CPU使用率与任务的CPU使用率进行比较是一个谬误。

如果没有您的任务正在进行的操作的详细信息(无论是访问文件,还是等待互斥锁等),都很难确定发生了什么。

您可以做的一件事是在您的任务中添加Stopwatch实例,并使用它来打印每次调用所用的时间。将运行任务的结果与DoWorkSequentialParallelForEach进行比较 - 无论方法如何,每次调用都应花费相同的时间。如果ParallelForEach运行的任务花费的时间更长,则可能表示您有一个互斥的互斥锁,需要用另一种锁定方法替换。

答案 1 :(得分:0)

您可能希望在Parallel.Foreach调用的ParallelOptions参数中将MaxDegreeOfParallelism设置为4。如果不这样做,dotnet4会使用很多工作线程;他们的管理和同步开销可能有点浪费。我有类似的问题,这对我有用。

http://msdn.microsoft.com/en-us/library/system.threading.tasks.paralleloptions.aspx

另外,在这里保持简单。请记住,当您使用严格的并行性时,您每秒的记录(cpu核心吞吐量)与每季度的记录(程序员生产率)进行折衷。