C#多线程代码CPU使用率过高

3

我在编写高质量多线程代码方面的知识不是很丰富。最近我开始参与一个需要用到这方面技术的项目。我编写了下面的代码,它能够按照我的要求工作,但是CPU使用率非常高。我认为这可能是由于我使用线程的方式不正确导致的。如果有人能指出下面代码中的缺陷,并告诉我如何修复以降低CPU使用率,我将不胜感激。

var numberOfMinutes = Convert.ToInt32(ConfigurationManager.AppSettings["NumberOfMinutesToRun"]);
var traversals = DbLayer.GetTraversals().ToList();
var numberOfThreads = Convert.ToInt32(ConfigurationManager.AppSettings["NumberOfThreads"]);
var threads = new List<Thread>(numberOfThreads);
var counter = 1;
var s = new Stopwatch();
s.Start();
var sync = new object();
while (s.Elapsed < TimeSpan.FromMinutes(numberOfMinutes))
{
    for (var i = 0; i < (numberOfThreads - threads.Count); i++)
    {
        var counter1 = counter; // due to closure.
        var traversal = traversals.FirstOrDefault(t => t.Id == counter1);
        var threadStart = new ThreadStart(new CallHelper(traversal).Migrate);
        var i1 = i;
        threadStart += () =>
                       {
                            threads.RemoveAt(i1);
                       };
        threads.Insert(i, new Thread(threadStart) {IsBackground = true});
        threads[i].Start();
        lock (sync)
        {
            counter++;
            if (counter > 6)
            {
                counter = 1;
            }
        }
    }
}
s.Stop();

我更新了代码,展示了我希望的所需内容。traversals集合仅包含6个项目。计数器是为了确保线程在traversals集合中旋转每个6个项目。CallHelper类只是在每个遍历上执行非常长时间的任务。该应用程序旨在使用可配置的线程数量和可配置的时间量在6个不同的对象上执行长时间运行的任务。希望我已经填好了足够的空白。


2
请提供最小化、完整化和可验证的示例以重现问题。http://stackoverflow.com/help/mcve - Fabjan
2
我不确定这段代码的目的是什么。这里的目标是什么?CallHelper().Migrate 是做什么用的?counter 的目的是什么?为什么要使用 while 循环和 for 循环来生成线程? - Ron Beyer
你应该使用任务并行库来管理线程,而不是试图手动操作它。(特别是如果你不是这方面的专家。) - xxbbcc
3
如果这不是一个关键的循环,那么使用Thread.Sleep(1)可以大大降低CPU利用率。 - sumeet kumar
1
我投票关闭此问题,因为它过于特定于提问者,对其他人没有用处。(抱歉,我找不到最近讨论使用关闭原因的元帖。) - ashes999
显示剩余3条评论
1个回答

1

有很多在线资源可用于编写良好的和高效的多线程代码。 "良好"通常指的是工作稳定且健壮的代码。对于高效的代码,请使用嵌入式资源。

我只是扫描了一下您的代码,但发现了各种问题,并可以提出建议。

  1. 使用线程池。建立和销毁线程非常昂贵。
  2. 尽可能少地重复循环(如上所述)。
  3. 需要延迟时,请使用睡眠而不是繁忙的循环。
  4. 使用非平凡代码测试效率。如果您针对平凡代码进行测试,您的利用率将被程序(而不仅仅是线程)的设置和拆除所主导,这是非常昂贵的并且会支配CPU利用率。
  5. 测量您感兴趣的代码的利用率,并排除您不感兴趣的部分,例如应用程序的设置和拆除。

我接受了这个答案,因为你是正确的。上面的代码有一些“问题”,因为你的输入非常有帮助,所以我已经重写了内部循环,CPU 使用率很低,但吞吐量非常好。我还在内部循环的结尾添加了 Thread.Sleep(1000)。我也会采纳你的建议,学习如何使用“线程池”。非常感谢你。 - marocano1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接