繁体   English   中英

回收线程以提高C#中递归调用的并行性

[英]Recycling threads to increase parallelism in recursive calls in C#

我在C#中有一个任务,需要递归计算树状结构中项目的属性。 基本上,我只是进行递归深度优先搜索,但是使用线程来并行化过程。 这意味着,从树的根开始,我启动N线程,为根的每个子项分配一个(最多可用线程,我们将其称为L )。 因此,如果N严格大于L ,则我将等待(N - L)根子节点等待处理,随着功能完全返回,这些子节点最终会逐渐发生,线程终止并回收用于处理下一个根子元素(如果还有任何未处理的元素)。

我只是在考虑一个或多个原始线程的运行时间相对较长的场景,以至于其他根子代(及其子代)在此之前或某个线程有时间完成之前有时间要处理。 这意味着我将不执行任何工作而具有潜在的可工作线程。

我想要实现的是实际使用这些线程来加速运行时间更长的执行路径。 我在考虑Open MPI ,实际上您可以始终使所有可用线程动态地处理其余任务。 这意味着,在每次调用递归方法之前,我都应该以某种方式检查是否所有根子对象都已被处理(因为它们是优先级),并且在这种情况下,生成递归调用的线程版本,然后移动继续下一个。

我试图在下面的图表(很差)中说明这种行为(其中每个横向分支都是递归方法调用/返回)。 第一张图片显示了thread2完成速度比thread1快得多的情况,然后只是简单地躺在周围而没有任何其他贡献。 第二张图片显示了所需的行为,在该行为中,在进行下一个递归调用之前,我们实际上使用可用线程将其线程化,然后继续下一个子级。 n级部分只是意味着它可以在递归中更深入。

您是否知道有什么方法可以在C#中促进此过程? 关于代码的并行化(就构造,数据结构等而言),最好的策略是什么? 另外,是否有一种简单的方法可以“减少”(汇总)计算结果?

线程无用地铺设这样更好

只需使用线程池,而不是创建自己的线程。 让每个节点由一个线程池任务处理。 然后,线程池将处理创建/删除线程,以便它有足够的线程来处理分配给它的操作的平均吞吐量,而不会使线程长时间闲置。

我认为您应该考虑将TPL库用于这种方法,可能与您自己实现的TaskScheduler类一起使用。 我认为这将适合您,因为:

  1. Tpl库在内部使用ThreadPool因此您无需担心系统资源管理。 默认的任务计划程序基于.NET Framework 4 ThreadPool,它提供了用于负载平衡的工作窃取

  2. 您可以将子任务附加到父任务 ,这将覆盖算法的递归部分,如下所示:

     using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { var parent = Task.Factory.StartNew(() => { Console.WriteLine("Parent task executing."); var child = Task.Factory.StartNew(() => { Console.WriteLine("Attached child starting."); Thread.SpinWait(5000000); Console.WriteLine("Attached child completing."); }, TaskCreationOptions.AttachedToParent); }); parent.Wait(); Console.WriteLine("Parent has completed."); } } // The example displays the following output: // Parent task executing. // Attached child starting. // Attached child completing. // Parent has completed. 
  3. 可以通过CancellationToken 任务,因此您可以轻松删除完整的子级集合以返回到第一级任务。 您也可以实现自己的TaskScheduler并使用它来确定下一个应该运行的任务。 有关如何创建和使用自定义任务计划程序的更多信息,请参见如何:创建限制并发性的任务计划程序 有关自定义调度程序的其他示例,请参见MSDN Code Gallery网站上的Parallel Extensions Samples

  4. TPL有几种新的公共类型,可在并行和顺序方案中使用。 其中包括System.Collections.Concurrent命名空间中的几个线程安全,快速和可伸缩的集合类,以及几个新的同步类型,例如System.Threading.SemaphoreSystem.Threading.ManualResetEventSlim ,它们比以前的版本更高效。特定类型的工作负载。 .NET Framework 4中的其他新类型,例如System.Threading.BarrierSystem.Threading.SpinLock ,提供了早期版本中不提供的功能。 有关更多信息,请参见《并行编程的数据结构》
  5. 您可以对该算法使用最新的C#功能async/await ,因此您的代码不仅可以并行执行,而且可以异步执行。
  6. 不能肯定地说对aggregate意味着什么,但是我认为TPL Dataflow命名空间可以为您提供帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM