运行最大线程:自动调整性能

时间:2011-08-02 11:22:11

标签: c# multithreading

我正在开发一个应用程序,它可以扫描数千个结构的副本; ~1 GB RAM。速度很重要。

     ParallelScan(_from, _to);  //In a new thread

我手动调整线程数:

     if (myStructs.Count == 0) { threads = 0; }
     else if (myStructs.Count < 1 * Number.Thousand) { threads = 1; }
     else if (myStructs.Count < 3 * Number.Thousand) { threads = 2; }
     else if (myStructs.Count < 5 * Number.Thousand) { threads = 4; }
     else if (myStructs.Count < 10 * Number.Thousand) { threads = 8; }
     else if (myStructs.Count < 20 * Number.Thousand) { threads = 12; }
     else if (myStructs.Count < 30 * Number.Thousand) { threads = 20; }
     else if (myStructs.Count < 50 * Number.Thousand) { threads = 30; }
     else threads = 40;

我刚刚从头开始编写它,我需要为另一个CPU等修改它。我想我可以编写一个更聪明的代码,如果CPU现在可用,它会动态启动一个新线程:

  • 如果CPU不是%100,则启动N线程
  • 测量CPU或线程处理时间&amp;修改/估计N
  • 循环直到扫描所有struct array

有没有人认为“我做过类似的事情”或“我有更好的主意”?

更新:解决方案

    Parallel.For(0, myStructs.Count - 1, (x) =>
    {
         ParallelScan(x, x); // Will be ParallelScan(x);

    });

我确实修剪了大量的代码。谢谢大家!

更新2:结果

扫描10K模板的时间

  • 1个主题:500毫秒
  • 10个主题:300毫秒
  • 40个主题:600毫秒
  • 任务:100毫秒

3 个答案:

答案 0 :(得分:5)

标准答案:使用任务(TPL),而不是线程。任务需要Fx4。

您的ParallelScan可以使用Parallel.Foreach( ... )或PLINQ(.AsParallel())。

TPL框架包括一个调度程序,ForEach()使用分区程序来适应CPU核心和负载。您的问题最有可能通过标准组件解决,但您可以编写自定义调度程序和分区程序。

答案 1 :(得分:3)

实际上,如果CPU只有两个核心(即使每个核心都支持超线程),你将无法从跨越50个线程中获益。如果由于每隔一段时间就会发生的上下文切换,实际上会运行较慢

这意味着您应该选择Task Parallel Library (.NET 4),这样可以有效地使用所有可用内核。

除此之外,无论摩尔定律如何,改善搜索算法的渐近持续时间对于大量数据可能更有价值。

<强> [编辑]

如果您不能/不愿意使用.NET 4 TPL,您可以首先获取系统中当前逻辑处理器数的信息(使用Environment.ProcessorCount或检查{ {3}}详细信息)。根据该数字,您可以对数据进行分区并跨越固定数量的线程。这比检查CPU利用率要简单得多,并且应该防止创建不必要的线程,这些线程无论如何都是饥饿的。

答案 2 :(得分:2)

好的,抱歉继续,但首先要编译我的评论:

  • 除非你有一个非常非常好的理由认为扫描这些结构需要花费的时间超过几微秒而且真的非常重要,所以进行这种优化不是一个好主意。如果你真的想这样做,你应该每个核心有一个线程。但是真的 - 不要。如果它只是50,000个结构而你正在做一些简单的事情,那就不要打扰了。
  • 仅供参考,开始一个新线程需要花费大量时间(一秒钟的可衡量部分,几毫秒)。
  • 此操作需要多长时间?对你来说,优化这样的多线程是非常不可能的。它会给你带来最糟糕的改善。通过更好的算法可以获得更好的改进,或者不必依赖于这种奇怪的发明多线程方案。

我对你的表演固定感到困惑,部分原因是因为你说你正在查看50,000个结构(一个非常快速和简单的操作),部分是因为你正在使用结构。没有装箱是值类型,如果你在线程周围传递它们,你就是复制数据而不是引用,即使用更多内存。我的观点是,这是大量的数据/内存,除非结构很小,在这种情况下,你可以对它们做什么样的处理,只需要考虑并行40多个线程?

如果性能真的非常重要并且您的目标,并且您不是简单地尝试将其作为一项精彩的工程练习,那么分享您正在进行的处理类型的信息。