【问题标题】:Limitation in the number of repeated calls for OTL's Parallel.ForEachOTL 的 Parallel.ForEach 的重复调用次数限制
【发布时间】:2015-04-17 17:53:32
【问题描述】:

我开始使用 OTL 进行多线程处理,并获得了很大的帮助!

各种使用Parallel.ForEach都成功了。但现在我遇到了一个无法解释的案件。

请看下面简单完整的代码:

program test;
{$APPTYPE CONSOLE}
uses
  OtlParallel;
var
  i: integer;
begin
  for i := 1 to 1251 do
    Parallel.ForEach(0, 0).Execute(
      procedure (const num: integer)
      begin
      end);
end.

当迭代次数超过1250时,出现错误:

'System Error. Code: 1816. Not enough quota is available to process this command'.

我会误解 OTL 的任何基本用法吗?

【问题讨论】:

  • 主线程被线程发布的空消息阻塞。见stackoverflow.com/q/25103602/576719
  • @LURD 谢谢。我认识到该链接讲述了一个相关问题,但这对我来说有点困难。我总是通过像上面示例这样的简单实现来利用 ForEach,并且不关心任何消息。有没有什么简单的方法可以在 ForEach 期间清理消息?
  • 不幸的是,我对 OTL 的内部工作原理知之甚少,无法提出解决方案。我最近看到了几个类似的问题,所以@gabr 或许可以解释一下。
  • 在循环中每次调用Parallel.ForEach() 后尝试调用CheckSynchronize。如果它有效,那将是一个创可贴,而不是解决方案。
  • 您使用的是哪个版本的Delphi,哪个版本的OTL?在我遇到 60 个线程限制而不是你的限制之前,我能够将限制提高很多。但是,您构建循环的方式并没有多大意义。你想达到什么目的?传统上,您会使用像 Parallel.ForEach(1,1251) 这样的 ForEach 循环。

标签: multithreading delphi omnithreadlibrary


【解决方案1】:

该问题源于 OTL 内部的一些(可能有问题的)设计解决方案,目前无法解决(除非通过在主线程中处理消息,正如其他人所说)。

无论如何,我建议您进一步重构您的方法。例如,您可以创建一个只有一个并行工作器的BackgroundWorker 抽象,然后创建 2000 个工作项并将它们发送到 BackgroundWorker。在后台工作人员的 Execute 方法中,您可以使用 Parallel.ForEach 来处理任务。

或者您可以创建一个具有多个并行任务(= 内核数)的 BackgroundWorker,然后在每个任务中运行一个正常的 for 循环。这可能会给您带来最快的性能。

顺便说一句,如果您以简单的形式使用 Parallel.ForEach,那么新的 Parallel.&For 性能会更好。它没有 ForEach 的所有花里胡哨,但速度要快得多。

【讨论】:

  • 我尝试使用 BackgroundWorker:BGWorker := Parallel.BackgroundWorker.NumTasks(1).Execute,然后,for i := 1 to 2000 do BGWorker.Schedule(BGWorker.CreateWorkItem(i)); 但在第 1251 次迭代时,它也会导致相同的错误。也许我按照你的指示做错了?
  • 我可能错过了一个简单的解决方案。在迭代内的Parallel.ForEach 下方添加Application.ProcessMessages; 消除了错误。这个解决方案可能是正确的方法吗?我实际上在我的真实代码中使用ForEach 和一个类作为参数,但它也可以转换为使用For。如果ForForEach快很多,希望能用。但很抱歉我找不到使用Parallel.&For 的说明。请告诉我在哪里可以找到它?
  • @TYK 是的,其他人已经在 cmets 中对您的问题表示处理消息会有所帮助。我在答案的第一段中也有我。 Paralell.For 记录在源代码中。我很确定我写了一篇关于它的文章,但我在网上的任何地方都找不到它。奇怪的。当我找到它时,我会在这里发布链接。
  • 非常感谢@gabr。我没有足够的 win 应用程序经验,并且专注于数学目的,所以我不知道如何处理此类消息。无论如何,我很高兴现在有一个解决方案!非常感谢您提供宝贵的工具。
  • @TYK 有关 Parallel.For 的使用示例,请查看 57_For 演示(OTL repo/distribution 的一部分)。要与 Parallel.ForEach 进行速度比较,请运行 58_ForVcForEach 演示(没有调试器,它会大大降低线程创建速度)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多