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

(0)

相关推荐

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

    前言 在 PowerShell 中可以轻松的执行后台任务并且让多个后台任务并行执行.本文介绍 PowerShell 中 Job 相关的一些命令,并通过 demo 演示如何在后台同时执行多个任务.下面话不多说了,来一起看看详细的介绍吧. PowerShell 中执行后台任务的模式 下图描述了在 PowerShell 中执行后台任务的进程模型(此图来自互联网): 首先我们需要一个 PowerShell 进程执行与用户交互的命令,比如执行 Start-Job 命令运行一个后台任务.每一个这样的后台任务

  • PowerShell中使用Get-ChildItem命令读取目录、文件列表使用例子和小技巧

    本文介绍一个PowerShell中使用Get-ChildItem这个cmdlet来获取目录下的文件列表.Get-ChildItem是获取子项目的意思,可以获取一个目录下的文件和子目录. 在DOS系统下,我们想查看一个目录下有哪些子目录和文件,我们可以通过dir命令来实现.在PowerShell中,dir命令貌似仍然可用.但洪哥告诉你,这个dir已经不是cmd.exe中的那个dir了,它是Get-ChildItem这个cmdlet的别名.也就是说,使用Get-ChildItem和使用dir得到的效

  • Docker run 命令的使用方法详解

    注意,本文基于最新的Docker 1.4文档翻译. Docker会在隔离的容器中运行进程.当运行 docker run命令时,Docker会启动一个进程,并为这个进程分配其独占的文件系统.网络资源和以此进程为根进程的进程组.在容器启动时,镜像可能已经定义了要运行的二进制文件.暴露的网络端口等,但是用户可以通过docker run命令重新定义(译者注:docker run可以控制一个容器运行时的行为,它可以覆盖docker build在构建镜像时的一些默认配置),这也是为什么run命令相比于其它命

  • Python命令行解析模块详解

    本文研究的主要是Python命令行解析模块的相关内容,具体如下. Python命令行常见的解析器有两种,一是getopt模块,二是argparse模块.下面就解读下这两种解析器. getopt模块 这个模块可以帮助脚本解析命令行参数,一般是sys.argv[1:].它遵循着Unix的getopt()函数相同的约定(用-/--指定命令参数).这个模块提供两个函数(getopt.getopt()/getopt.gnu_getopt())和一个参数异常(getopt.GetoptError). 这里重

  • linux传输文件命令 rz 和 sz详解

    一. 概述 rz,sz是Linux/Unix同Windows进行ZModem文件传输的命令行工具. 优点就是不用再开一个sftp工具登录上去上传下载文件. Zmodem协议是针对modem的一种错误校验协议.利用Zmodem协议,可以在modem上发送512字节的数据块.如果某个数据块发生错误,接受端会发送"否认"应答,因此,数据块就会被重传.它是Xmodem 文件传输协议的一种增强形式,不仅能传输更大的数据,而且错误率更小.包含一种名为检查点重启的特性,如果通信链接在数据传输过程中中

  • java使用FFmpeg合成视频和音频并获取视频中的音频等操作(实例代码详解)

    FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序. ffmpeg命令参数如下: 通用选项 -L license -h 帮助 -fromats 显示可用的格式,编解码的,协议的... -f fmt 强迫采用格式fmt -I filename 输入文件 -y 覆盖输出文件 -t duration 设置纪录时间 hh:mm:ss[.xxx]格式的记录时间也支持 -ss position 搜索到指定的时间 [-]hh:mm:ss[.xxx]的格式也支持 -title

  • Android中实现ping功能的多种方法详解

    使用java来实现ping功能. 并写入文件.为了使用java来实现ping的功能,有人推荐使用java的 Runtime.exec()方法来直接调用系统的Ping命令,也有人完成了纯Java实现Ping的程序,使用的是Java的NIO包(native io, 高效IO包).但是设备检测只是想测试一个远程主机是否可用.所以,可以使用以下三种方式来实现: 1. Jdk1.5的InetAddresss方式 自从Java 1.5,java.net包中就实现了ICMP ping的功能. 使用时应注意,如

  • Windows 版本Git命令行的使用详解

    Git的使用基本教程 git安装 官网 msysgit.github.io(百度搜索git下载地址也行)下载 git安装(路径选择你的路径或者默认也行) 步骤中:出现选项注意选择Use git from git bash only(其他默认一路下一步就行了) 最后配置环境变量(目的就是在CDM窗口任意目录都可以执行git命令行) path:D:\Asoftware\java\Git\bin 详情请参考:https://www.jb51.net/article/191327.htm git配置账户

  • Linux下tcpdump命令解析及使用详解

    简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具.tcpdump可以将网络中传送的数据包的"头"完全截获下来提供分析.它支持针对网络层.协议.主机.网络或端口的过滤,并提供and.or.not等逻辑语句来帮助你去掉无用的信息. 实用命令实例 默认启动 tcpdump 普通情况下,直接启动tcpdump将监视第一个网络接口上所有流过的数据包. 监视指定网络接口的数据包 tcpdum

  • Maven build 命令介绍的使用详解

    常用命令: 打包:mvn package 编译:mvn compile 清空:mvn clean(清除编译后目录,默认是target目录) 运行测试:mvn test 安装jar包到本地仓库中:mvn install 跳过测试:mvn xxx -DskipTests 1.创建 Maven 工程 ①.在 src/main/java 新建包 com.ys.maven,然后在这个包中创建类 HelloMaven.java package com.ys.maven; public class Hello

随机推荐