并行执行任务
Posted zqj-blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并行执行任务相关的知识,希望对你有一定的参考价值。
最近在写一些powershell脚本时候遇到一个问题,那就是要解压十几个zip文件,这样仅执行完解压操作差不多5min的时间就过去了,严重影响了效率,这时就想到了使用多线程的方法来执行这个解压操作,经过学习了解到powershell提供了一个Start-Job命令来实现并行执行。接下来对这个命令做一个总结。
一、真实案例
以我之前遇到的问题作为示例来介绍这个命令,先贴出源方案,串行执行。c:zipfile目录下有十几个zip文件,需要对文件进行解压,按照原有的方案是遍历整个目录,一次解压,耗时5min。
foreach ( $i in ls c:zipfile*.zip) { .7z.exe x $i }
利用start-job后的代码:
foreach ( $i in ls c:zipfile*.zip) { Start-Job -ScriptBlock{ .7z.exe x $i } }
使用并行执行的方案后,执行时长缩小到了1min。
二、熟练使用start-job及相关配套命令
1、start-job
后台运行sleep命令,并且为这个任务命名为“sleep”。
Start-Job -ScriptBlock { sleep 10 } -Name sleep
在后台运行命令前首先将1赋值给$a,然后再去执行输出$a的操作,最后命名为test,-InitializationScript参数的作用是任务开始前需要执行的。
Start-Job -InitializationScript { $a = 1 } -ScriptBlock { echo $a } -Name test
若需要后台执行脚本,使用-FilePath参数即可
Start-Job -FilePath .a.ps1
2、get-job
获取当前所有后台进程的状态信息,starte是任务的执行状态,“Completed”表示任务完成,“Failed”表示任务执行失败,“Running”表示正在运行的,“Stopped”表示任务停止。
PS C:> Get-Job Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 29 Job29 BackgroundJob Completed True localhost mkdir c:a... 31 test1 BackgroundJob Failed False localhost slepp 20
3、stop-job
停止后台运行的某个任务,下面的例子是后台运行一个睡20s的任务,得知该任务的id是43,然后停止id=43的任务,再去查看后台任务。如果知道后台任务的名称,也可以根据名字来停止(参数是-Name)
PS C:Usersill> Start-Job -ScriptBlock{ sleep 20} Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 43 Job43 BackgroundJob Running True localhost sleep 20 PS C:Usersill> Stop-Job -id 43 PS C:Usersill> Get-Job Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 43 Job43 BackgroundJob Stopped False localhost sleep 20
4、receive-job
我们在使用start-job后台执行任务的时候,往往是不会显示命令的执行结果,此时可以使用receive-job命令查看它的结果
PS C:Usersill> Start-Job -ScriptBlock { echo "1" } -Name "ok" Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 45 ok BackgroundJob Running True localhost echo "1" PS C:Usersill> Receive-Job -Name ok 1
5、wait-job
再回到最初的案例,对文件解压完后,需要将各个解压文件移动到某个位置,但是使用start-job将每个解压任务放到后台,此时系统会接着执行后续的操作,这时出现了文件还没有解压完成,就已经开始对解压文件进行操作,导致脚本异常。针对这个问题需要用到wait-job命令。
PS C:> Start-Job -ScriptBlock { sleep 5 } -Name s1 Start-Job -ScriptBlock { sleep 6 } -Name s2 Start-Job -ScriptBlock { sleep 7 } -Name s3 echo "satrt" Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 47 s1 BackgroundJob Running True localhost sleep 5 49 s2 BackgroundJob Running True localhost sleep 6 51 s3 BackgroundJob Running True localhost sleep 7 satrt
我们可以看到三个后台任务和输出“start”几乎是同时执行的,加入wait-job后
PS C:> Start-Job -ScriptBlock { sleep 5 } -Name s1 Start-Job -ScriptBlock { sleep 6 } -Name s2 Start-Job -ScriptBlock { sleep 7 } -Name s3 Wait-Job * echo "satrt" Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 53 s1 BackgroundJob Running True localhost sleep 5 55 s2 BackgroundJob Running True localhost sleep 6 57 s3 BackgroundJob Running True localhost sleep 7 57 s3 BackgroundJob Completed False localhost sleep 7 55 s2 BackgroundJob Completed False localhost sleep 6 53 s1 BackgroundJob Completed False localhost sleep 5 satrt
加入wait-job命令后的现象是,等待所有的后台命令执行完成后,才去执行echo “start”。此时就明白了wait-job的作用了,那就是等待执行的任务完成后再去执行其他的。
其中wait-job中-Id和-Name可以指定特定的任务。
若不用wait-job命令可以下面的代码来监控后台任务是否执行完
Remove-Job * #测试计时开始 $start_time = (Get-Date) Start-Job -ScriptBlock { sleep 9; Write-Host "Hello myJob1."; } -Name "myJob1" Start-Job -ScriptBlock { sleep 5; Write-Host "Hello myJob2."; } -Name "myJob2" $taskCount = 2 while($taskCount -gt 0) { foreach($job in Get-Job) { $state = [string]$job.State if($state -eq "Completed") { Write-Host($job.Name + " 已经完成") Receive-Job $job $taskCount-- Remove-Job $job } } sleep 1 } "所有任务已完成" #得出任务运行的时间 (New-TimeSpan $start_time).totalseconds
6、remove-job
删除后台运行的任务,前提条件是该后台任务是停止状态
PS C:> Get-Job Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 53 s1 BackgroundJob Completed False localhost sleep 5 55 s2 BackgroundJob Completed False localhost sleep 6 57 s3 BackgroundJob Completed False localhost sleep 7 59 rm BackgroundJob Completed False localhost sleep 20 PS C:> Remove-Job -Name rm PS C:> Get-Job Id Name PSJobTypeName State HasMoreData Location Command -- ---- ------------- ----- ----------- -------- ------- 53 s1 BackgroundJob Completed False localhost sleep 5 55 s2 BackgroundJob Completed False localhost sleep 6 57 s3 BackgroundJob Completed False localhost sleep 7 PS C:> Remove-Job * PS C:> Get-Job
以上是关于并行执行任务的主要内容,如果未能解决你的问题,请参考以下文章