BeginInvoke() 返回的 AsynchronousObject 的 IsComplete 全部为真

IsComplete of AsynchronousObject returned by BeginInvoke() all true

我目前正在学习 Powershell 中的 运行spaces(我的最终目标是建立一个作业调度系统)来做到这一点我写了一个基本的脚本来学习和使用 运行空格。

我期望发生的事情:

我预计当我 运行 代码到注释行时,这将在 RunspacePool 中排队 8 个作业和 运行 它们,运行 最多一次 2 个。

运行 单行 $JobList.AsynchronousObject 几次,然后应该看到越来越多的 IsComplete 标志从 false 变为 true 作为工作由于 Start-Sleep 命令,它们每个需要 20 秒才能完成。

BeginInvoke 命令显然 returns 一个实现 IAsycResult 接口的对象。

https://docs.microsoft.com/en-us/dotnet/api/system.iasyncresult?redirectedfrom=MSDN&view=netframework-4.8#examples

IAsyncResult 的评论中提到轮询 IsComplete 属性 以查看异步操作是否已完成,尽管这并不理想,但我在下面出于学习目的尝试这样做.

实际:

所有 IsComplete 标志在 运行 代码顶部 true 秒后出现,这不是我所期望的

问题:

IsComplete 标志是否仅表示脚本是否已开始执行,也许这就是为什么它们在排队后 true 秒后全部出现的原因?

对于任何人能够提供的进一步阅读的任何帮助或参考,我深表感谢。

非常感谢

尼克

#Set up runspace
    $RunspacePool = [runspacefactory]::CreateRunspacePool()
    $RunspacePool.SetMinRunspaces(1)
    $RunspacePool.SetMaxRunspaces(2)

#Create arraylist to hold references to all the instances running jobs
    $JobList = New-Object System.Collections.ArrayList

#Queue up 8 jobs that will take 20 seconds each to complete
#Add the job details to the list so I can poll it's IsComplete property
    $RunspacePool.Open()
    1..8 | ForEach {
        Write-Verbose "Counter: $_" -Verbose
        $PowershellInstance = [powershell]::Create()
        $PowershellInstance.RunspacePool = $RunspacePool
        [void]$PowershellInstance.AddScript({
            Start-Sleep -Seconds 20
            $ThreadID = [appdomain]::GetCurrentThreadId()    
            Write-Verbose "$ThreadID thread completed" -Verbose
        })
        $AsynchronousObject = $PowershellInstance.BeginInvoke()
        $JobList.Add(([PSCustomObject]@{
            Id = $_
            PowerShellInstance = $PowershellInstance
            AsynchronousObject = $AsynchronousObject
        }))
    }
#----------------------------------------------

#List IsComplete should show true as jobs become complete
    $JobList.AsynchronousObject

#Clean up 
    $RunspacePool.Close()
    $RunspacePool.Dispose()

没有问题。您忘记了异步的真正含义。

当您启动异步作业时,它们不会阻塞当前线程(也就是您当前的 PowerShell 提示),它们会创建一个新线程并且 运行 从那里。异步作业的全部意义在于,您可以 运行 一次完成多个任务。

所以发生的事情是创建运行空间,一切都设置好,作业排队并开始 运行 在新线程中,然后它继续进行(一切都是异步的并且 运行ning 在单独的线程)。然后它继续执行最后三行:

#List IsComplete should show true as jobs become complete
    $JobList.AsynchronousObject

#Clean up 
    $RunspacePool.Close()
    $RunspacePool.Dispose()

这会杀死运行空间并对其进行处理,从而 "completing" 作业。

如果您 运行 注释行之前的所有内容。 然后 从 PowerShell 提示开始观察 $JobList.AsynchronousObject,然后您将看到它按预期逐步完成作业。

完成后,您可以执行最后两行来关闭和处理您的 运行空间。

如果你想让事情等着你,你必须看看作业等待功能。