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

本文关键字:性能 调整 线程 运行 | 更新日期: 2023-09-27 18:04:09

我正在开发一个应用程序,可以扫描数千个结构体的副本;~ 1gb 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或线程处理时间&修改/估计N
  • 循环直到扫描所有struct数组

是否有人认为"我做过类似的事情"或"我有更好的主意"?

UPDATE: The solution

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

我确实修改了大量代码。感谢的人!

UPDATE 2: Results

10K模板的扫描时间

  • 1线程:500 ms
  • 10个线程:300 ms
  • 40线程:600 ms
  • 任务:100 ms

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

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

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

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

实际上,如果您的CPU只有两个内核(即使每个内核都支持超线程),那么跨越50个线程不会获得太多好处。如果运行起来会慢一些,因为每隔一段时间就会发生上下文切换。

这意味着您应该使用任务并行库(。. NET 4),它负责有效地使用所有可用的内核。

除此之外,改进搜索算法的渐近持续时间可能对大量数据更有价值,而不考虑摩尔定律。

[编辑]

如果你不能或不愿意使用。net 4 TPL,你可以从获取有关当前系统中逻辑处理器数量的信息开始(使用Environment.ProcessorCount或检查此答案以获取详细信息)。基于这个数字,您可以对数据进行分区,并跨越固定数量的线程。这比检查CPU利用率要简单得多,并且应该防止创建不必要的线程,这些线程无论如何都会饿死。

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

  • 除非你有非常、非常、非常、非常好的理由认为扫描这些结构体将花费超过几微秒的时间,而且这真的、真的、真的很重要,否则做这种优化不是一个好主意。如果你真的想这样做,你应该为每个核心设置一个线程。但真的——不要。如果它只是5万个结构体,并且你正在用它们做一些简单的事情,那就不要麻烦了。
  • 供参考,启动一个新线程需要大量的时间(可测量的一秒的一部分,几毫秒)。
  • 这个操作需要多长时间?像这样优化多线程对您来说不大可能有用。它只会给你带来最差的改善。更好的算法将获得更好的改进,或者不必依赖于这个奇怪的发明多线程方案。

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

如果性能真的是非常重要的和你的目标,你不只是试图做一个很好的工程练习,请分享你正在做的处理的信息。