当所有并行工作单元必须同时运行时,任务是否是合适的选择?

时间:2015-03-04 09:44:09

标签: c# .net multithreading c#-4.0 task-parallel-library

任务(TPL)是自.NET 4.0以来执行并行性的推荐方法,因为它们是更高的抽象,让运行时更好地优化事物。

但是在所有工作单位必须同时发生的情况下,TPL仍然是/最佳选择吗?

我的用例是生成PsExec的多个实例(大约10个),以便在多个远程PC上同时运行相同的进程,并等待每个实例退出。任何'优化'通过TPL导致并行运行所有实例将是灾难性的。

这个用例是否超出了TPL的范围,我发布线程会更好吗?

我知道你不能一次执行更多的线程而不是你的核心,但Windows会通过切片运行比核心更多的线程,这是可以接受的,但是调度任何线程在其他线程完成之前不会运行。“ / p>

3 个答案:

答案 0 :(得分:1)

来自documentation

  

TPL动态调整并发度,以最有效地使用所有可用的处理器

但你的情景,

  

“所有工作单位必须立即发生”

因此,没有保证所有进程都是并行化的。 paralalization的数量将取决于你拥有的资源量(在这种情况下处理器/线程)。即使有资源,您需要并行化的单位的数量也会阻碍成功。

另外:

TPL使用线程池,这意味着您的工作排队到线程管理器中的线程。但你说明了

  

“但安排任何线程在其他线程完成之前不会运行   不是“

当你的工作单位超过线程池中可用的线程数时,这可能会被违反。

实际上我的意见是处理基本线程,适合于这样一个微妙/敏感的任务。

答案 1 :(得分:1)

当TPL启动或任务代码在什么线程上时,它由TPL决定。如果线程池恰好在注入新线程时很慢,那么你的任务可能会延迟很多秒。

通过使用TaskCreationOptions.LongRunning,您可以使当前版本的TPL立即为该任务创建新线程。很明显,你仍然没有任何关于同时执行的保证,但似乎近似的同时执行对你来说已经足够了。

我估计TaskCreationOptions.LongRunning现在保证在未来版本中创建新线程以及兼容性原因。应用程序肯定已经开始依赖各种细节,如线程ID和线程本地状态。这是永远不会改变的(鉴于.NET具有高兼容性版本的历史)。

您应该比TaskCreationOptions.LongRunning更喜欢Task Thread,因为它与其他代码组合得更好,并且具有更好的错误处理。

答案 2 :(得分:1)

TPL的行为与您的场景并不相关 - 您不需要TPL并行生成X命令行进程,您可以使用简单的{{1循环。只有当进程生成时,for才会等待进程终止并返回。

Process.Start连接到远程计算机并生成进程所需的时间非常长,以至于在第一台远程计算机启动之前,您将能够生成数十个(如果不是数百个)进程处理请求。

如果绝对必须启动数千个进程并且for循环的几毫秒延迟不会发生,那么可以使用psexec并行生成多个进程。您必须收集Process对象 由所有Task.Run(()=>Process.Start...)次呼叫返回,以便监控它们完成。

虽然产生一个流程比直接通过代码进行网络调用要昂贵得多。您可以创建远程会话,例如。 as shown here并远程执行管道(命令)。

您可以使用InvokeAsync而不是Invoke来异步开始执行每个管道,无论是在for循环中还是使用TPL。要检测命令是否已完成,您需要监视管道的PipelineStateInfo属性或订阅其StateChanged事件。

您可以使用TaskCompletionSource包装事件并等待所有管道完成。

修改

或许更好的选择是通过执行Start-Job来安排远程计算机上的作业在特定时间点运行,而不是尝试同时生成所有进程。这避免了很多编排问题。

另一种选择是让Powershell本身execute the commands in parallel使用Powershell工作流程。工作流程还允许您并行执行相同的脚本on all items in a collection

编辑2

似乎Powershell工作流程已经支持仅使用the PSComputerName parameter在多台计算机上生成脚本。复制自文档:

Task.Run