关于检测脚本块是否绑定到其他Runspace的SessionState及相关代码致命错误的技术问询
最近我在测试PowerShell多Runspace相关的脚本时,遇到了一个偶发的致命崩溃问题,折腾了好一阵都没完全搞明白,想跟大家请教下原因和解决办法。先给大家看下我运行的代码:
foreach ($i in 1..100) { $sb = {'bound_to_parent_runspace'} . $sb | Out-Null 1..2 | ForEach-Object { Start-ThreadJob ` -ArgumentList ([pscustomobject]@{ScriptBlock = $sb}) ` -ScriptBlock { param($arg1) 'child_runspace' . $arg1.ScriptBlock } | Receive-Job ` -Wait ` -ErrorAction Stop } }
这段代码偶尔会直接导致PowerShell进程退出,弹出的致命错误信息如下:
An error has occurred that was not properly handled. Additional information is shown below. The PowerShell process will exit.
Unhandled exception. System.InvalidOperationException: Stack empty.
at System.Collections.Generic.Stack1.ThrowForEmptyStack() at System.Collections.Generic.Stack1.Pop()
at System.Management.Automation.DlrScriptCommandProcessor.OnR...
我大概能猜到问题可能出在脚本块的Runspace绑定上——我在父Runspace里定义的$sb脚本块,默认是绑定到父Runspace的SessionState的,然后我把它传递给Start-ThreadJob创建的子Runspace去执行。这种跨Runspace执行绑定脚本块的操作,会不会导致内部的状态栈出现异常?尤其是当循环次数多、频繁创建销毁子Runspace的时候,就容易触发这个栈空的错误。
想请教下大家:
- 这个错误的根本原因是不是脚本块的Runspace绑定冲突?
- 有没有办法检测一个脚本块是否已经绑定到某个Runspace的SessionState上?
- 有没有更安全的方式在子Runspace中执行父Runspace定义的脚本逻辑,避免这种致命错误?
我自己尝试过把脚本块转换成字符串,在子Runspace里用[scriptblock]::Create()重新创建,好像能避免这个问题,但不确定这是不是最优解,也想听听大家的建议。
备注:内容来源于stack exchange,提问作者alx9r

