Powershell中要执行并行操作的话除了上一篇博客提到的Background Job以外,还可以使用Runspace的方式。
每个powershell脚本运行在一个Runspace上,使用多个Runspace相当于同时跑多个powershell脚本。
基本用法
$powershell=[powershell]::Create() #创建Runspace
$powershell.AddScript({Sleep -Seconds 10}) #添加一个可以执行的脚本
#添加参数的两种方式
$a=1
$b={param1=2,param2=3}
$powershell.AddArgument($a)
$powershell.AddParameters($b) #为多个参数赋值比较方便
#开始执行脚本,会返回一个执行对象
$asyncObj=$powershell.BeginInvoke()
#结束执行脚本,从执行对象中获取结果
$powershell.EndInvoke($asyncObj)
用Runspace并行
这里用一个数组之间赋值的应用来场景来说明下Runspace怎么用于Powershell并行。假设数组B赋值给给数组A
并行的基本方式
1. 将数组B按长度分成n份
2. 为Runspace创建一个大小为n的Runspace池(类似线程池)
3. 为池子里的Runspace分配工作,即每个Runspace负责赋一部分的值
4. 将最终结果整合
$B_size=100
$B=0..($B_size-1)
$A=@() #B copy to A
$loop_num=10
$runspace_num= 10 #threads
#脚本块
$ScriptBlock = {
Param (
[Object[]]$part_B
)
$arr=@()
$count=$part_B.Count
for($i=0;$i -lt $count;$i++){
$arr+=@($part_B[$i])
}
return $arr
}
#创建一个资源池,指定多少个runspace可以同时执行
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, $runspace_num)
$RunspacePool.Open()
$Jobs = @()
for($i=0;$i -lt $runspace_num;$i++){
$delta=$B_size/$runspace_num
$part_B=$B[($i*$delta)..(($i+1)*$delta-1)]
$Job = [powershell]::Create().AddScript($ScriptBlock).AddArgument($part_B)
$Job.RunspacePool = $RunspacePool
$Jobs += New-Object PSObject -Property @{
Pipe = $Job
AsyncObj = $Job.BeginInvoke()
}
}
#循环输出等待的信息.... 直到所有的job都完成
Write-Host "Waiting.." -NoNewline
Do {
#Write-Host "." -NoNewline
#Start-Sleep -Seconds 1
} While ( $Jobs.AsyncObj.IsCompleted -contains $false)
Write-Host "All jobs completed!"
#输出结果
$Results = 0..($Throttle-1)
$Job_ID=0
ForEach ($Job in $Jobs)
{
$JobRes=$Job.Pipe.EndInvoke($Job.AsyncObj)
$Results[$Job_ID]=$JobRes
$A+=$JobRes
#$Result=$Job.Pipe.EndInvoke($Job.AsyncObj)
#$Results[$Job_ID] = $Result[1]
$Job_ID++;
}
$A.Count
Runspace可以通过RunspacePool来复用Runspace,所以它可以极大地避免频繁创建删除的开销,所以效率其实是要比Background Job要更高的。