本文介绍了RunSpace及其关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用使用RunSpace的脚本时,我发现它占用越来越多的系统内存.据我了解,这是由于打开RunSpace在完成时不会关闭的事实.它们保留在内存中,累积了兆字节.

While working with a script that uses a RunSpace, I found that it takes up more and more system memory. As far as I understand, this is due to the fact that open RunSpace do not close when completed. They remain in memory, accumulating megabytes.

如何正确关闭RunSpace?但是,我不知道需要多长时间-1秒或1个小时.完成后自行关闭.

How to close the RunSpace, correctly? However, I do not know how long it will take - 1 second or 1 hour. Closes itself when completed.

作为示例,我将提供任意脚本.

As an example, I will give arbitrary scripts.

第一个脚本是我如何完成RunSpace的关闭(它显然不起作用).

The first script is how I do the closing of the RunSpace as it is completed (and it apparently does not work).

$Array = 1..10000

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

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

$PowerShell.Runspace = $RunSpace

[void]$PowerShell.AddScript({

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

   # Closing the Process, which should close the RunSpace, but this does not happen.
   $Powershell.Runspace.Dispose()
   $PowerShell.Dispose()
})

$Async = $PowerShell.BeginInvoke()

# Other jobs in the main thread...

从系统内存来看,第二个脚本似乎更正确.但是,由于Start-Sleep 10冻结了主进程,因此它在生命中当然不适用.

The second script seems to be more correct, judging by the system memory. However, of course it is not applicable in life, as the Start-Sleep 10 freezes the main Process.

$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...

请写信给我关闭RunSpace的正确方法.谢谢你

Please write me the correct way to close the RunSpace as it is completed. Thanks you

推荐答案

尝试从内部处置运行空间,听起来好像是一个坏主意-实际上,如果我在PowerShell Core中尝试这样做7.0-rc2,我的会话挂起.

Trying to dispose of a runspace from within that runspace sounds like a bad idea - in fact, if I try this in PowerShell Core 7.0-rc2, my session hangs.

听起来您要在脚本完成后自动处置运行空间 .

It sounds like you want to dispose of the runspace automatically, on completion of the script.

您可以为 System.Management.Automation.PowerShell.InvocationStateChanged 事件,在其中可以检查CompletedFailed状态并关闭运行空间,然后:

You can set up an event handler for the System.Management.Automation.PowerShell.InvocationStateChanged event, inside of which you can check for the Completed and Failed states and close the runspace then:

注意: Register-ObjectEvent 必须是用于订阅事件;原则上可以通过将脚本块直接传递给PowerShell实例上的.add_InvocationStateChanged()进行订阅,但是当您以后调用.EndInvoke()时,执行将挂起.

Note: Register-ObjectEvent must be used to subscribe to the event; while it is possible in principle to subscribe by passing a script block directly to .add_InvocationStateChanged() on the PowerShell instance, execution will hang when you later call .EndInvoke().

# 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.'

以上内容应产生以下输出:

The above should yield the following output:

Starting script execution via SDK...
Doing things...
Invocation state: Running
Invocation state: Completed
Disposing of runspace.
Collecting script-execution results...
1
2
3
1
2
3
Done.

这篇关于RunSpace及其关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-15 08:41