这篇文章主要给大家介绍了关于PowerShell中Job相关命令及并行执行任务的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

前言

在 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:简单实现并行任务的脚本

最新资讯
蔚来汽车李斌:山村里的大学生,创新大潮中的创业者

蔚来汽车李斌:山村里的

从山村里走出来的大学生,到创业创新大潮中的活跃面孔乃
刘作虎:手机行业波涛汹涌 要坚持商业本质相信时间

刘作虎:手机行业波涛汹

一加手机今日举行一加五周年特别活动。一加科技CEO刘
直击|阿里巴巴将试水知产服务市场 推知产开放平台

直击|阿里巴巴将试水

阿里巴巴今日宣布,将打造阿里知产开放平台,首站将试水阿
一块屏幕很难改变教育的命运,弹幕或许可以

一块屏幕很难改变教育

这成就究竟有多大程度上可以归功于远程教育的应用,是非
直击|知乎宣布架构调整 任命前蜜芽合伙人孙伟为CFO

直击|知乎宣布架构调

知乎创始人、CEO周源发布全员信,宣布组织架构调整为前
电连技术起诉乐视移动案12月17日开庭 索赔765.9万元

电连技术起诉乐视移动

电连技术公告称,公司5月委托广东格明律师事务所就与乐
最新文章
PowerShell使用match操作符来筛选数组

PowerShell使用match

本文介绍PowerShell中使用match操作符,配合正则表达式
PowerShell 语音计算器实现代码

PowerShell 语音计算

带中文发音功能的计算器程序,支持鼠标和小键盘输入,支持
通过DNS TXT记录执行powershell

通过DNS TXT记录执行p

这篇文章主要介绍了通过DNS TXT记录执行powershell的
如何防范PowerShell代码注入漏洞绕过受限语言模式

如何防范PowerShell代

这篇文章主要介绍了如何防范PowerShell代码注入漏洞绕
PowerShell管道入门必看篇(管道例子大全)

PowerShell管道入门必

下面小编就为大家带来一篇PowerShell管道入门必看篇(
使用 powershell 创建虚拟机

使用 powershell 创建

Azure PowerShell 模块用于从 PowerShell 命令行或脚