任务(TPL)是自.NET 4.0以来执行并行性的推荐方法,因为它们是更高的抽象,让运行时更好地优化事物。
但是在所有工作单位必须同时发生的情况下,TPL仍然是/最佳选择吗?
我的用例是生成PsExec的多个实例(大约10个),以便在多个远程PC上同时运行相同的进程,并等待每个实例退出。任何'优化'通过TPL导致不并行运行所有实例将是灾难性的。
这个用例是否超出了TPL的范围,我发布线程会更好吗?
我知道你不能一次执行更多的线程而不是你的核心,但Windows会通过切片运行比核心更多的线程,这是可以接受的,但是调度任何线程在其他线程完成之前不会运行。“ / p>
答案 0 :(得分:1)
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