使用后台作业执行多个任务从先前的技巧中看不是非常高效,它在处理每个后台作业返回结果时将会浪费很多性能。一个更有效的方法是使用进程内的任务。他能分别单独的执行任务与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
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
@Codecook, “它在处理每个后台作业返回结果时将会浪费很多性能”。这个我深有体会,之前需要做测试,循环访问某个连接,我竟然写出来了这么一段脚本,逻辑类似:Start-Job -ScriptBlock { while($true) { Invoke-WebRequest http://www.pstips.net } }然后去吃午饭了,回来后,机器几乎死机了。原因就是每次执行的输出start-job都会保存起来,越积越多,几乎耗光内存。
前段时间,有500个任务需要执行,单线程,需要20分钟;如果用job多线程,系统内存扛不住。最后只能,写个循环,设置后台任务不超过20个,完成的任务,取出数据,然后移除,这样就快多了。
不要说PowerShell,即使是C#编程,应当也鲜有下开500个线程的例子吧。除了内存,应当还有CPU,硬盘读取速度,网络带宽等很多瓶颈。一半5-10个就差不多了。也可以尝试下Parallel Foreach,把开多少个子线程的决定权交给PowerShell本身:http://www.pstips.net/powershell-parall.html
workflow,前几天在群里讨论过,学习下
相继执行这3个任务从Start-Sleep中看至少需要花费12秒。但是这个脚本仅执行了5秒多一点。脚本执行5秒多,可以看到,“相继执行这3个任务从Start-Sleep中看至少需要花费12秒”,你是怎么计算的?
“顺序执行这三个任务,光计算Sleep的时间,忽略Get-Service ,应当至少需要12= (3+4+5)秒”.这样理解好一点!”顺序(consecutively )”两个字不能少。
奥
有道理
function test-task ([string] $message) {
$outstr = ((Get-Date).ToString() + $message)
$outstr
$outstr | Out-File -FilePath “D:\test-task.txt”
}
# test-task task1 单独执行有效果
$task1 = { test-task task1 } #放在线程里执行没效果
$thread1 = [PowerShell]::Create()
$job1 = $thread1.AddScript($task1).BeginInvoke()
您好,如上面的代码,请问在线程里为何执行函数没有任何效果?
异步编程模式(APM)不支持取消,临时用用还成,远远没有 Jobs 管理方便
如果在C#中调用的化,这样的APM处理还是有点用的,因为它可以把更多的控制权暴漏给C#。
问下,BeginInvoke或者start-job,支持异步回调吗?job完成后就触发特定的方法,而不是一直在那儿wait-job或while{}。
试下另外一个重载函数: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)