我很想在PowerShell中使用Start-ThreadJob
、Start-Job
和Start-Process
测试异步任务的性能/有用性。我有一个包含大约100个zip文件的文件夹,因此进行了以下测试:
New-Item "000" -ItemType Directory -Force # Move the old zip files in here
foreach ($i in $zipfiles) {
$name = $i -split ".zip"
Start-Job -scriptblock {
7z.exe x -o"$name" .\$name
Move-Item $i 000\ -Force
7z.exe a $i .\$name\*.*
}
}
这样做的问题是,它会为所有100个zip启动作业,这可能太多了,所以我想设置一个值$numjobs
,比如5,我可以改变它,这样只有$numjobs
会同时启动,然后脚本将检查所有5个作业在下一个5块开始之前结束。然后,我想根据$numjobs
的值来查看CPU和内存
我如何告诉一个循环只运行5次,然后等待作业完成后再继续?
我发现等待工作完成很容易
$jobs = $commands | Foreach-Object { Start-ThreadJob $_ }
$jobs | Receive-Job -Wait -AutoRemoveJobchange
但是我如何等待Start-Process
任务结束呢?
虽然我想使用Parallel-ForEach
,但我工作的企业将在未来3-4年内与PowerShell 5.1紧密相连,我预计没有机会安装PowerShell 7.x(尽管我很好奇自己在家里的系统上测试Parallel-ForEach
以比较所有方法)。
3条答案
按热度按时间yiytaume1#
ForEach-Object -Parallel
和Start-ThreadJob
具有限制可以同时运行的线程数量的内置功能,这同样适用于Runspace及其RunspacePool,这是两个cmdlet在幕后使用的。Start-Job
不提供这样的功能,因为每个作业都在一个单独的进程中运行,而不是前面提到的在同一进程中的不同线程中运行的cmdlet。我个人也不认为它是并行的替代方案,它非常慢,在大多数情况下线性循环会比它快。在某些情况下,序列化和反序列化也可能是一个问题。如何限制运行线程数?
这两个cmdlet都为此提供了
-ThrottleLimit
参数。代码看起来如何?
如何在只有PowerShell 5.1且无法安装新模块的情况下实现相同的功能?
RunspacePool提供了相同的功能,无论是通过它的
.SetMaxRunspaces(Int32)
方法,还是通过针对RunspaceFactory.CreateRunspacePool
重载之一提供maxRunspaces
限制作为参数。代码看起来如何?
请注意,对于所有示例,尚不清楚7zip代码是否正确,此答案试图演示如何在PowerShell中完成异步,而不是如何压缩文件/文件夹。
下面是一个帮助函数,它可以简化并行调用的过程,尝试模拟
ForEach-Object -Parallel
,并与PowerShell 5.1兼容,尽管不应该被视为一个强大的解决方案:注意This Q&A提供了一个更好和最强大的替代下面的功能。
它是如何工作的一个例子:
2vuwiymt2#
要添加到Santiago Squarzon's helpful answer:
下面是辅助函数
Measure-Parallel
,它允许您比较以下并行方法的速度:Start-Job
:Start-ThreadJob
-附带 PowerShell(Core)(v6+);可通过Install-Module ThreadJob
在Windows PowerShell v5.1中安装:Start-Job
轻得多,同时提供相同的功能;另外避免了由于跨进程串行化/反串行化而导致的类型保真度的潜在损失。ForEach-Object
-Parallel
-仅在PowerShell(Core)7.0+中提供:Start-ThreadJob
是一个简化的 Package 器,支持直接管道输入和直接输出,始终同步整体执行(等待所有启动的线程)。Start-Process
注意事项:
7z.exe
),那么Start-Process
方法将执行得最好,因为它没有作业管理的开销。然而,如上所述,这种方法有基本的局限性。Start-ThreadJob
或ForEach-Object -Parallel
,则不需要采用这种方法。示例
Measure-Parallelism
调用,对比了这些方法的运行时性能:运行PowerShell 7.2.6的macOS机器的示例输出(时间因许多因素而异,但比率应提供相对性能的感觉):
结论:
ForEach-Object -Parallel
增加的线程/作业管理开销最小,其次是Start-ThreadJob
Start-Job
,由于需要一个 * 额外的 * 子进程-用于运行每个任务的隐藏PowerShell示例-明显较慢。在Windows上,性能差异似乎更加明显。源代码:**
*重要信息:
*函数 * 硬编码 * 示例输入对象以及要调用的外部程序-您必须根据需要自行编辑;硬编码的外部程序在本例中是平台原生shell(在Windows上是
cmd.exe
,在类Unix平台上是/bin/sh
),它被传递一个命令来简单地 echo 每个输入对象。Start-Process
方法,除非您通过PowerShell CLI显式调用该块-但在这种情况下可以使用Start-Job
)。5
,可以通过-BatchSize
修改;对于基于线程的方法,批处理大小也用作-ThrottleLimit
参数,即允许同时运行的线程数量的限制。默认情况下,运行 * 单个 * 批处理,但您可以通过将并行运行的总数传递给-JobCount
间接请求多个批处理-Approach
参数选择方法,该参数支持Job
、ThreadJob
、Process
、ForEachParallel
和All
,这些方法组合了前面的所有方法。-Approach
,则进入 interactive 模式,在该模式下(重复)提示您选择所需的方法。7rtdyuoh3#
您可以在foreach循环中添加一个计数器,如果计数器达到所需的值,则中断循环
或者使用Powershells Foreach-Object
如果你想批量处理整个数组,并等待每个批处理完成,你必须保存
Start-Job
返回的对象,并将其传递给Wait-Job
,如下所示:根据设计,数组具有固定的长度,这就是为什么我用
$items = $items[$batchsize..($items.Length)]
重写整个数组