Powershell 运行空间及其关闭

Powershell 运行空间及其关闭,powershell,runspace,powershell-sdk,Powershell,Runspace,Powershell Sdk,在处理使用运行空间的脚本时,我发现它占用了越来越多的系统内存。据我所知,这是因为开放式运行空间在完成时不会关闭。它们保留在内存中,积累兆字节 如何正确关闭运行空间?然而,我不知道需要多长时间-1秒或1小时。完成后自动关闭 作为一个例子,我将给出任意脚本 第一个脚本是如何在运行空间完成时关闭它(显然它不起作用) 从系统内存来看,第二个脚本似乎更正确。但是,它当然不适用于生活,因为Start Sleep 10冻结了主进程 $Array = 1..10000 $PowerShell = [Power

在处理使用运行空间的脚本时,我发现它占用了越来越多的系统内存。据我所知,这是因为开放式运行空间在完成时不会关闭。它们保留在内存中,积累兆字节

如何正确关闭运行空间?然而,我不知道需要多长时间-1秒或1小时。完成后自动关闭

作为一个例子,我将给出任意脚本

第一个脚本是如何在运行空间完成时关闭它(显然它不起作用)

从系统内存来看,第二个脚本似乎更正确。但是,它当然不适用于生活,因为
Start Sleep 10
冻结了主进程

$Array = 1..10000

$PowerShell = [PowerShell]::Create()
$RunSpace = [Runspacefactory]::CreateRunspace()
$RunSpace.Open()

$RunSpace.SessionStateProxy.SetVariable('Array', $Array)

$PowerShell.Runspace = $RunSpace

[void]$PowerShell.AddScript({

   # Fill the system memory so that it can be seen in the Task Manager.
   $Array += $Array
   $Array
})

$Async = $PowerShell.BeginInvoke()

Start-Sleep 10

$PowerShell.EndInvoke($Async) | Out-Null
$PowerShell.RunSpace.Dispose()
$PowerShell.Dispose()

# Other jobs in the main thread...

请写信告诉我在运行空间完成时关闭运行空间的正确方法。感谢您尝试从运行空间中处置运行空间听起来是个坏主意-事实上,如果我在PowerShell Core 7.0-rc2中尝试此操作,我的会话将挂起

听起来好像您希望在脚本完成后自动处理运行空间

您可以为事件设置事件处理程序,在其中可以检查
已完成
失败
状态,然后关闭运行空间:

注意:必须用于订阅活动;虽然原则上可以通过将脚本块直接传递到
PowerShell
实例上的
.add\u InvocationStateChanged()
来订阅,但当您稍后调用
.EndInvoke()
时,执行将挂起

上述操作应产生以下输出:

正在通过SDK启动脚本执行。。。
做事情。。。
调用状态:正在运行
调用状态:已完成
处理运行空间。
正在收集脚本执行结果。。。
1.
2.
3.
1.
2.
3.
完成。
$Array = 1..10000

$PowerShell = [PowerShell]::Create()
$RunSpace = [Runspacefactory]::CreateRunspace()
$RunSpace.Open()

$RunSpace.SessionStateProxy.SetVariable('Array', $Array)

$PowerShell.Runspace = $RunSpace

[void]$PowerShell.AddScript({

   # Fill the system memory so that it can be seen in the Task Manager.
   $Array += $Array
   $Array
})

$Async = $PowerShell.BeginInvoke()

Start-Sleep 10

$PowerShell.EndInvoke($Async) | Out-Null
$PowerShell.RunSpace.Dispose()
$PowerShell.Dispose()

# Other jobs in the main thread...
# Note: I'm using a small array so that the output of the code better
#       shows what's happening.
$Array = 1..3

$PowerShell = [PowerShell]::Create()
$RunSpace = [Runspacefactory]::CreateRunspace()
$RunSpace.Open()

$RunSpace.SessionStateProxy.SetVariable('Array', $Array)

$PowerShell.Runspace = $RunSpace

$null = $PowerShell.AddScript( {

    # Fill the system memory so that it can be seen in the Task Manager.
    $Array += $Array
    $Array

  })

# Set up an event handler for when the invocation state of the runspace changes.
# Note: Register-ObjectEvent with -Action returns an event-job object, which
#       we don't need in this case.
$null = Register-ObjectEvent -InputObject $PowerShell -EventName InvocationStateChanged -Action {
  param([System.Management.Automation.PowerShell] $ps)

  # NOTE: Use $EventArgs.InvocationStateInfo, not $ps.InvocationStateInfo, 
  #       as the latter is updated in real-time, so for a short-running script
  #       the state may already have changed since the event fired.
  $state = $EventArgs.InvocationStateInfo.State

  Write-Host "Invocation state: $state"
  if ($state -in 'Completed', 'Failed') {
    # Dispose of the runspace.
    Write-Host "Disposing of runspace."
    $ps.Runspace.Dispose()
    # Speed up resource release by calling the garbage collector explicitly.
    # Note that this will pause *all* threads briefly.
    [GC]::Collect()
  }      

}

# Kick off execution of the script and
# let the event handler dispose of the runspace on completion.
Write-Host 'Starting script execution via SDK...'
$asyncResult = $PowerShell.BeginInvoke()

# Perform other processing.
Write-Host 'Doing things...'
1..1e5 | ForEach-Object { }

# Finally, get the results from the script execution.
# NOTE: Even though the runspace has likely already been disposed, collecting
#       the results seemingly still works.
Write-Host 'Collecting script-execution results...'
$PowerShell.EndInvoke($asyncResult)

# Note that you'll have to create and assign a *new* runspace to 
# $PowerShell.Runspace if you want to execute further code.

Write-Host 'Done.'