当前位置: 代码网 > it编程>前端脚本>Powershell > PowerShell中Job相关命令及并行执行任务详解

PowerShell中Job相关命令及并行执行任务详解

2024年05月15日 Powershell 我要评论
前言在 powershell 中可以轻松的执行后台任务并且让多个后台任务并行执行。本文介绍 powershell 中 job 相关的一些命令,并通过 demo 演示如何在后台同时执行多个任务。下面话不

前言

在 powershell 中可以轻松的执行后台任务并且让多个后台任务并行执行。本文介绍 powershell 中 job 相关的一些命令,并通过 demo 演示如何在后台同时执行多个任务。下面话不多说了,来一起看看详细的介绍吧。

powershell 中执行后台任务的模式

下图描述了在 powershell 中执行后台任务的进程模型(此图来自互联网):

首先我们需要一个 powershell 进程执行与用户交互的命令,比如执行 start-job 命令运行一个后台任务。每一个这样的后台任务都会在一个新启动的 powershell 进程中执行。所以,如果我们同时启动三个后台任务,那么一共有四个 powershell 进程在同时运行。

job 相关的命令

start-job 命令会启动一个运行在后台的任务。注意,每通过 start-job 命令运行一个任务都会创建一个单独的 powershell 进程。

stop-job 命令用来停止一个正在运行的后台任务(由 start-job 启动的任务)。

get-job 命令用来获得当前 session 中的后台任务对象。

wait-job 命令阻塞当前的执行流程,等待指定的后台任务执行结束。

receive-job 命令用来获得后台执行任务的执行结果。比如在一个后台任务结束时,可以通过 receive-job 来得到结果,并输出任务执行时的 output。

remove-job 命令删除当前 session 中的已经完成的任务。当一个任务运行结束后,它并不会被自动删除,除非你调用 remove-job 命令进行删除,或者是关闭这个 session。如果使用 remove-job 删除一个正在运行的任务,命令会运行失败。此时需要先使用 stop-job 命令先停止任务,然后再用 remove-job 进行删除。

在后台执行任务

如果只是启动一个后台执行的任务,不需要知道任务执行的结果,也不关心任务何时执行结束,那么仅仅使用 start-job 命令启动任务的执行就可以了:

> start-job -scriptblock { sleep 5 }

启动单个任务并等待任务结束

多数情况下我们是需要知道任务的结束时间的,此时可以通过 wait-job 命令阻塞执行流程,直到等待的任务结束:

> start-job -scriptblock { sleep 5; write-host "hello world."; } | wait-job

注意:上面的内容是由 wait-job 命令输出的,当时任务的状态为 "completed"。

更进一步,我们还想要获得任务执行过程中的输出。这时我们就需要用到 receive-job 命令。你可以在任务启动后的任何时刻执行 receive-job 命令,但是如果想要得到完整的输出,就需要在任务结束后调用,此时需要配合 wait-job 命令一起使用:

$job = start-job -scriptblock { sleep 5; write-host "hello world."; }
wait-job $job
receive-job -job $job

把上面的代码保存到文件 mytask.ps1 中执行:

receive-job 命令输出了我们在后台执行的任务的 output。

在后台执行多个任务并等待结束

因为 start-job 命令是非阻塞的,所以理论上我们可以执行任意多次从而启动很多的后台任务。和等待单个任务相同,仍然可以使用 wait-job 命令来等待所有的任务结束,不过此时需要配合 get-job 命令一起使用:

> get-job | wait-job

更常用的方式是我们在 while 循环中不断的检查任务的状态,当所有任务的状态都是 "completed" 时表示全部任务执行结束:

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

把上面的代码保存到 mytask.ps1 文件中并执行:

代码中我们给每个任务起了名字,并在 while 循环中不断的使用 get-job 命令检查任务当前的状态,如果发现任务的状态为 "completed",就通过 remove-job 命令删除它,并在删除前打印任务的名称和 output。

封装一个执行后台任务的函数

下面我们用封装一个简单的函数来并行执行多个任务:

function run-tasks
{
 param
 (
  $taskarr,
  $parallelcount=1
 )
 #测试计时开始
 $starttime = (get-date)
  #移除本次会话中已有的所有后台任务
 remove-job *
 # 使用变量 $taskcount 保存还没有执行完成的任务数
 $taskcount = $taskarr.length
 
 #判断设定的并行任务数是否超过当前任务队列中的任务数
 if($parallelcount -gt $taskarr.length)
 {
  $parallelcount = $taskarr.length
 }
 #启动初始任务
 foreach($i in 1..$parallelcount)
 {
  start-job $taskarr[$i - 1] -name "task$i"
 }
 #初始任务完成后开始的任务
 $nextindex = $parallelcount
 #当任务队列中还有任务时不断轮询已建立的任务,当一个后台任务结束时删除这个任务,
 #然后从任务队列中取出下一个任务进行执行,然后等待所有任务执行完成。
 while(($nextindex -lt $taskarr.length) -or ($taskcount -gt 0))
 {
  foreach($job in get-job)
  {
   $state = [string]$job.state
   if($state -eq "completed")
   { 
    write-host($job.name + " 已经完成,结果如下:")
    receive-job $job
    remove-job $job
    $taskcount--
    if($nextindex -lt $taskarr.length)
    { 
     $tasknumber = $nextindex + 1
     start-job $taskarr[$nextindex] -name "task$tasknumber"
     $nextindex++
    }
   }
  }
  sleep 1
 }
 "所有任务已完成"
 #得出任务运行的时间
 (new-timespan $starttime).totalseconds
}

上面的函数会在后台执行用户的任务,然后等待所有的任务执行结束。并且用户可以指定同时执行的任务的个数,在任务执行完成后,输出任务的 output。接下来让我们尝试使用这个函数执行一些任务:

#定义 6 个任务
$task1 = {sleep 12; write-host "hello myjob1."; }
$task2 = {sleep 5; write-host "hello myjob2."; }
$task3 = {sleep 8; write-host "hello myjob3."; }
$task4 = {sleep 3; write-host "hello myjob4."; }
$task5 = {sleep 20; write-host "hello myjob5."; }
$task6 = {sleep 15; write-host "hello myjob6."; } 
#将 6 个任务写入到一个数组中作为任务队列
$taskarr = $task1, $task2, $task3, $task4, $task5, $task6
#运行数组中的任务,允许同时运行 4 个任务
run-tasks -taskarr $taskarr -parallelcount 4

下面是运行的结果:

总结

能够随心所欲的在后台执行任务是一件感觉非常棒的事情!当然,对于工作来说你能够把事情做得又快又好(又好可不敢说)。本文只是提供了一个简单的运行并行任务的 demo,省略了异常处理等重要内容,但这已经足够您开始 powershell 并行任务之旅了。

参考:

《windows powershell 实战第二版》
powershell:简单实现并行任务的脚本

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com