zoukankan      html  css  js  c++  java
  • 并行执行任务 Stat-Job

    最近在写一些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)
    {
    $command = ".7z.exe x $i" Start-Job -ScriptBlock{ $command }     #注意:在{}中不可以传入“.7z.exe x $i”类似这样命令与变量的结合体,{}接收的是类似$command这样的字符串或者是“.7z.exe x a.zip”这样的内容。否则会报错哦 }

      使用并行执行的方案后,执行时长缩小到了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
    

      以上的作用是等待所有后台任务结束后才会执行后续的操作,还有一种参数是-Any,它的作用是等待后台任务中任意一个介绍就会执行后续操作。

    Remove-Job *
    
    Start-Job -ScriptBlock{ sleep 2 } -Name a1
    Start-Job -ScriptBlock { sleep 30} -Name a2
    Wait-Job -Any *
    

      等上述执行完成后,查看get-job,可以看到“sleep 30”还在进行。即有一个后台任务结束后就不在等待!

    PS C:Windowssystem32> Get-Job
    
    Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                  
    --     ----            -------------   -----         -----------     --------             -------                  
    115    a1              BackgroundJob   Completed     False           localhost             sleep 2                 
    117    a2              BackgroundJob   Running       True            localhost             sleep 30 
    

       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
    

     三、start-job传入参数

       将参数传入start-job需要用到两个,一个是花括号中的param(),另一个是ArguementList,具体实例如下。

    PS C:> $a = "name"
    
    PS C:> $b = "bill"
    
    PS C:> Start-Job -ScriptBlock{ param($a,$b) echo "$a == $b" }  -ArgumentList $a,$b
    
    Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                  
    --     ----            -------------   -----         -----------     --------             -------                  
    67     Job67           BackgroundJob   Running       True            localhost             param($a,$b) echo "$a...
    
    
    PS C:> Receive-Job -id 67
    name == bill
    

      over!

     

     

      

     

     

  • 相关阅读:
    k8s keepalived haproxy 集群成功
    .Net Core 用 EntityFramework 读取 Oracle
    Fedora CoreOS 安装 非LInux专业国内第一手
    Docker 下的 Keepalived + Haproxy 高可用实现 1 实现结果演示
    第二篇 windows container 微软的原生容器
    第一篇 Windows docker 概述
    测试openLiveWrite写博客
    比特币勒索病毒肆虐,腾讯云安全专家给你支招
    WannaCry 勒索病毒用户处置指南
    pytorch 学习笔记之编写 C 扩展,又涨姿势了
  • 原文地址:https://www.cnblogs.com/zqj-blog/p/10120743.html
Copyright © 2011-2022 走看看