【问题标题】:Powershell: Unexpected results in Receive-JobPowershell:接收作业中的意外结果
【发布时间】:2012-08-18 12:40:19
【问题描述】:

我正在尝试更好地了解 powershell 如何处理作业。

这两篇文章都有很大帮助:

但是,使用以下示例脚本,我在调用 Receive-Job 时得到了意想不到的结果。我希望每行都有一个结果,但有时我会看到每行有多个结果或额外的空白回车。关于如何只写出每个作业从控制台流入的信息的任何想法?

$loops = 1..10
$jobs = new-object System.Collections.ArrayList

$loops | % {
    $jobs.add( 
        (start-job -ScriptBlock {
            param($list)
            $list | % {
                sleep -seconds (get-random -Maximum 3 -Minimum 1)
                write-host "Number is: $_"
            }
        } -ArgumentList (,$loops))
    ) | out-null
}


while ($jobs.count -gt 0)
{
    if ($jobs -ne $null)
    {
        $list = $jobs | ? { $_.HasMoreData -eq $true }
        $list | % { Receive-Job -Job $_ }
        $list2 = $jobs.Clone() | ? { $_.State -eq "Completed" }
        $list2 | % {
            $jobs.Remove($_) | out-null
        }
        $list = $null
    }
}

输出可以是……

数量是:1 数量是:1 数量是:2

有时……

数量是:1 数量是:2 号码是:1号码是:2 号码是:1号码是:2号码是:2

【问题讨论】:

    标签: multithreading powershell start-job powershell-jobs


    【解决方案1】:

    你把这件事复杂化了很多。您不需要所有这些循环来手动处理事情。您应该利用可用的 cmdlet。这应该可以实现您想要的基本功能:

    $loops = 1..10
    
    $scriptBlock = {
      param($list)
      $list | % {
        sleep -seconds (get-random -Maximum 3 -Minimum 1)
        write-host "Number is: $_"
      }
    }
    
    $jobs = $loops | % { start-job -ScriptBlock $scriptBlock -ArgumentList (,$loops) }
    
    $jobs | Wait-Job | Receive-Job
    

    但是,这会将所有输出组合在一起,而无法知道什么工作做了什么。而您使用 Write-Host 的事实意味着您实际上无法访问数据,它只是打印到屏幕上。

    如果您想实际存储或处理生成的作业输出,您可以执行以下操作:

    $loops = 1..10
    
    $scriptBlock = {
      param($list)
      $list | % {
        sleep -seconds (get-random -Maximum 3 -Minimum 1)
        "Number is: $_"  # don't use write-host, just output the string
      }
    }
    
    $jobs = $loops | % { start-job -ScriptBlock $scriptBlock -ArgumentList (,$loops) }
    
    $jobs | Wait-Job  # wait for all jobs to be complete
    $jobs |%{
       $output = $_ | Receive-Job
       # process $output here, do what you want with it
    }
    

    【讨论】:

    • 谢谢!你说得对,我把脚本过于复杂了。我倾向于在实验中这样做。您的示例运行良好,除非我想在作业运行时获取数据而不是调用等待作业怎么办?例如,我试图在作业运行时将任何输出(通过 write-host)从作业通过管道传输到主 powershell 控制台(这是我脚本底部所有循环的重点)。通过这样做,我是否会走上“这不是工作的目的/功能”的道路?是否应该在调用Receive-Job 之前等待所有作业完成?
    • 并不是说这不是工作的“目的”,只是这不是他们最擅长的,也不是您支持 cmdlet 的目的。您可以进行各种疯狂的循环和完成检查并获得一些“流式”行为,但这将非常复杂且容易出错。这对您来说是一个成本/收益决定。工作最擅长的是“我去做这个工作,我做完你可以处理结果”。如果您想要流式传输,您可以让每个作业写入不同的日志文件,然后启动“尾”进程来流式传输每个日志。
    • 谢谢您,您的帮助很大。在处理一些使用作业的示例项目时,我会牢记您的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 1970-01-01
    • 2019-05-11
    相关资源
    最近更新 更多