RunSpace 及其关闭
The RunSpace and its closure
在处理使用 RunSpace 的脚本时,我发现它占用的系统内存越来越多。据我了解,这是因为打开的 RunSpace 在完成时不会关闭。它们保留在内存中,累积兆字节。
如何正确关闭RunSpace?但是,我不知道需要多长时间——1 秒或 1 小时。完成后自行关闭。
举个例子,随便给个脚本
第一个脚本是我如何在 RunSpace 完成时关闭它(显然它不起作用)。
$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
冻结了主进程。
$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 的正确方法。谢谢
尝试从 中处理一个运行空间,这个运行空间听起来不是个好主意 - 事实上,如果我在 PowerShell Core 7.0-rc2 中尝试这样做,我的会话就会挂起。
听起来你想自动处理运行空间,在脚本完成时。
您可以为 System.Management.Automation.PowerShell.InvocationStateChanged
事件设置一个事件处理程序,在其中您可以检查 Completed
和 Failed
状态并关闭运行空间然后:
注意:必须使用Register-ObjectEvent
订阅事件;虽然原则上可以通过将脚本块直接传递给 PowerShell
实例上的 .add_InvocationStateChanged()
来订阅,但当您稍后调用 .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.'
以上应该产生以下输出:
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 的脚本时,我发现它占用的系统内存越来越多。据我了解,这是因为打开的 RunSpace 在完成时不会关闭。它们保留在内存中,累积兆字节。
如何正确关闭RunSpace?但是,我不知道需要多长时间——1 秒或 1 小时。完成后自行关闭。
举个例子,随便给个脚本
第一个脚本是我如何在 RunSpace 完成时关闭它(显然它不起作用)。
$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
冻结了主进程。
$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 的正确方法。谢谢
尝试从 中处理一个运行空间,这个运行空间听起来不是个好主意 - 事实上,如果我在 PowerShell Core 7.0-rc2 中尝试这样做,我的会话就会挂起。
听起来你想自动处理运行空间,在脚本完成时。
您可以为 System.Management.Automation.PowerShell.InvocationStateChanged
事件设置一个事件处理程序,在其中您可以检查 Completed
和 Failed
状态并关闭运行空间然后:
注意:必须使用Register-ObjectEvent
订阅事件;虽然原则上可以通过将脚本块直接传递给 PowerShell
实例上的 .add_InvocationStateChanged()
来订阅,但当您稍后调用 .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.'
以上应该产生以下输出:
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.