【问题标题】:Running maximum threads: Automatic performance adjustment运行最大线程数:自动性能调整
【发布时间】:2011-08-02 11:22:10
【问题描述】:

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

     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 不是 %100,则启动 N 线程
  • 测量 CPU 或线程处理时间并修改/估计 N
  • 循环直到扫描所有结构数组

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

更新:解决方案

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

    });

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

更新 2:结果

10K 模板的扫描时间

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

【问题讨论】:

  • 除非你有一个非常、非常、非常好的理由认为扫描这些结构需要的时间不会超过几微秒,而且这真的、真的、真的很重要,否则这不是一个好主意做这种优化。如果你真的想这样做,你应该每个核心有一个线程。但真的 - 不要。如果它只有 50,000 个结构,而您正在用它们做一些简单的事情,请不要打扰。
  • 另外,您是否有一个名为Number.Thousand 的常量被定义为1000?就用1000或者叫Number.Thousand以外的名字,好像很多余?
  • 仅供参考,启动一个新线程需要很长时间(一秒的可测量部分,几毫秒)。
  • @Nime:你说的“容易切换”,你的意思是改变 Number.Thousand 以返回 1e6,例如?
  • 如果难以阅读,请使用_。例如int myVal = 1_000_000; 工作一百万就可以了

标签: c# multithreading


【解决方案1】:

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

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

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

【讨论】:

【解决方案2】:

实际上,如果您的 CPU 只有两个内核(即使每个内核都支持超线程),跨越 50 个线程并不会带来太多好处。由于上下文切换会不时发生,If 实际上会运行更慢

这意味着您应该选择Task Parallel Library (.NET 4),它会确保所有可用内核都得到有效使用。

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

[编辑]

如果您不能/不愿意使用 .NET 4 TPL,您可以从获取系统中当前逻辑处理器数量的信息开始(使用Environment.ProcessorCount 或查看this answer了解详细信息)。根据该数字,您可以对数据进行分区并跨越固定数量的线程。这比检查 CPU 利用率要简单得多,并且应该防止创建不必要的线程。

【讨论】:

    【解决方案3】:

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

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

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

    如果性能和您的目标确实非常重要,并且您不只是试图将其作为一项很好的工程练习,分享有关您正在执行哪种处理的信息。

    【讨论】:

    • 这是人脸识别过程。客户端:一个网络摄像头拍摄,提取人脸,生成一个 15KB 的“模板”。服务器端:应用程序扫描每个注册的模板(结构)以查找匹配项。现在我有 30 个人,每人平均 20 个模板,总共 500 个模板。我们的目标是 5000 人/服务器。
    • 目前我们的局域网中的服务器响应时间为 50 毫秒。我复制了超过 5 万个模板,其中扫描时间 > 3 秒。
    • 这是一个非常棒的例子,说明了您所要求的实际可用案例,非常感谢:) 面部识别处理是处理器密集型的,非常值得考虑横向扩展就像你一样。出于兴趣,您是要使用感知器 NN 路线,进行任何匹配/对齐/去偏斜,还是只是逐像素比较?
    • @Nime:一个澄清:每组“模板”都是从 Web 客户端发送到服务器的。通过 50 毫秒的 LAN 响应,您是否考虑了整个往返过程?那么这 3 秒是否对应于实际处理时间或完成一堆往返的时间?另外,您知道每个 Web 请求都从 ASP.NET 的线程池中获取自己的线程吗?
    • @Groo:50ms 包括发送和接收时间。如您所见,扫描时间约为 3 秒时并不那么重要。 3 秒内一个线程也不重要。我只向服务器发送一个活动模板,然后服务器查看模板数组/存档 - 大量结构所在的位置 - 进行匹配。还是谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    相关资源
    最近更新 更多