高效的PowerShell多线程 13


使用后台作业执行多个任务从先前的技巧中看不是非常高效,它在处理每个后台作业返回结果时将会浪费很多性能。一个更有效的方法是使用进程内的任务。他能分别单独的执行任务与Powershell类似,所以它不是按顺序返回值的。

下面例子使用Powershell线程运行了两个后台任务和一个前台任务,创建几个运行时间长点的任务,并且每个任务命令中添加使用Start-Sleep。

$start = Get-Date

$task1 = { Start-Sleep -Seconds 4; Get-Service }
$task2 = { Start-Sleep -Seconds 5; Get-Service }
$task3 = { Start-Sleep -Seconds 3; Get-Service }

# run 2 in separate threads, 1 in the foreground
$thread1 = [PowerShell]::Create()
$job1 = $thread1.AddScript($task1).BeginInvoke()

$thread2 = [PowerShell]::Create()
$job2 = $thread2.AddScript($task2).BeginInvoke()

$result3 = Invoke-Command -ScriptBlock $task3

do { Start-Sleep -Milliseconds 100 } until ($job1.IsCompleted -and $job2.IsCompleted)

$result1 = $thread1.EndInvoke($job1)
$result2 = $thread2.EndInvoke($job2)

$thread1.Runspace.Close()
$thread1.Dispose()

$thread2.Runspace.Close()
$thread2.Dispose()

$end = Get-Date
Write-Host -ForegroundColor Red ($end - $start).TotalSeconds

相继执行这3个任务从Start-Sleep中看至少需要花费12秒。但是这个脚本仅执行了5秒多一点。其结果保存为$result1, $result2和$result3。与后台作业对比,它在返回大数据用时将差不多。

原文地址:Running Background Jobs Efficiently

本文链接: https://www.pstips.net/running-background-jobs-efficiently.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

13 条评论 “高效的PowerShell多线程

  • 荔非苔

    @Codecook, “它在处理每个后台作业返回结果时将会浪费很多性能”。这个我深有体会,之前需要做测试,循环访问某个连接,我竟然写出来了这么一段脚本,逻辑类似:Start-Job -ScriptBlock { while($true) { Invoke-WebRequest http://www.pstips.net } }然后去吃午饭了,回来后,机器几乎死机了。原因就是每次执行的输出start-job都会保存起来,越积越多,几乎耗光内存。

    • qzuser

      前段时间,有500个任务需要执行,单线程,需要20分钟;如果用job多线程,系统内存扛不住。最后只能,写个循环,设置后台任务不超过20个,完成的任务,取出数据,然后移除,这样就快多了。

      • 荔非苔

        不要说PowerShell,即使是C#编程,应当也鲜有下开500个线程的例子吧。除了内存,应当还有CPU,硬盘读取速度,网络带宽等很多瓶颈。一半5-10个就差不多了。也可以尝试下Parallel Foreach,把开多少个子线程的决定权交给PowerShell本身:http://www.pstips.net/powershell-parall.html

  • 2843160902

    相继执行这3个任务从Start-Sleep中看至少需要花费12秒。但是这个脚本仅执行了5秒多一点。脚本执行5秒多,可以看到,“相继执行这3个任务从Start-Sleep中看至少需要花费12秒”,你是怎么计算的?

    • 荔非苔

      试下另外一个重载函数:System.IAsyncResult BeginInvoke[T](System.Management.Automation.PSDataCollection[T] input,System.Management.Automation.PSInvocationSettings settings, System.AsyncCallback callback, System.Object state)System.IAsyncResult BeginInvoke[TInput, TOutput](System.Management.Automation.PSDataCollection[TInput] input,System.Management.Automation.PSDataCollection[TOutput] output)