powershell - 如何在 ForEach-Object -Parallel 中传递自定义函数
问题描述
我找不到传递函数的方法。只是变量。
没有将函数放在 ForEach 循环中的任何想法?
function CustomFunction {
Param (
$A
)
Write-Host $A
}
$List = "Apple", "Banana", "Grape"
$List | ForEach-Object -Parallel {
Write-Host $using:CustomFunction $_
}
解决方案
解决方案并不像人们希望的那样简单:
function CustomFunction {
Param ($A)
"[$A]"
}
# Get the function's definition *as a string*
$funcDef = $function:CustomFunction.ToString()
"Apple", "Banana", "Grape" | ForEach-Object -Parallel {
# Define the function inside this thread...
$function:CustomFunction = $using:funcDef
# ... and call it.
CustomFunction $_
}
注意:此答案包含一个类似的解决方案,用于在脚本块中使用调用者范围内的ForEach-Object -Parallel
脚本块。
注意:如果您的函数是在模块中定义的,该模块位于模块自动加载功能已知的位置之一,您的函数调用将按原样工作
ForEach-Object -Parallel
,无需额外的努力 - 但每个线程都会产生(隐式) 导入模块。上述方法是必要的,因为除了当前位置(工作目录)和环境变量(适用于进程范围)之外,
ForEach-Object -Parallel
创建的线程看不到调用者的状态,尤其是变量和函数(以及不是定制的 PS 驱动器和导入的模块)。- 更新:js2010 的有用答案显示了一个更直接的解决方案,它通过 a
System.Management.Automation.FunctionInfo
获得Get-Command
,可以直接使用&
. 唯一需要注意的是,原始函数应该没有副作用,即应该完全基于参数或管道输入进行操作,而不依赖于调用者的状态,尤其是它的变量,因为这可能会导致线程安全问题。上面的字符串化技术隐式地防止了对调用者状态的任何有问题的引用,因为函数体是在每个线程的上下文中重建的。
- 更新:js2010 的有用答案显示了一个更直接的解决方案,它通过 a
从 PowerShell 7.1 开始,GitHub 上正在讨论一项增强功能,以支持按需将调用者的状态复制到线程,这将使调用者的函数可用。
请注意,没有辅助就凑合。$funcDef
变量并尝试重新定义函数$function:CustomFunction = $using:function:CustomFunction
很诱人,但$function:CustomFunction
它是一个脚本块,并且明确禁止使用带有$using:
范围说明符的脚本块。
但是,
$function:CustomFunction = $using:function:CustomFunction
可以与Start-Job
; 例如,请参阅此答案。它也适用于
Start-ThreadJob
, 你甚至可以这样做& $using:function:CustomFunction $_
,因为$using:function:CustomFunction
它被保存为脚本块(与 不同Start-Job
,它被反序列化为string,这本身就是令人惊讶的行为 - 请参阅GitHub 问题 #11698)。但是,尚不清楚design是否支持此行为,因为它受到上述相同的潜在跨线程问题的影响。
$function:CustomFunction
是命名空间变量表示法的一个实例,它允许您通过分配包含函数体的 a 或字符串来获取函数(它的主体作为[scriptblock]
实例)和设置(定义)它。[scriptblock]
推荐阅读
- xcode - 如何在 Xcode 构建设置中引用 git 存储库根目录?
- javascript - 如何注册变量属性更改并在 html 文件中显示该更改
- python - Python matplotlib堆积条形图——奇怪的结果
- javascript - Angular 8 /Firebase:使用电子邮件和密码创建用户时如何设置 displayName?
- python - 在 C++ 程序中嵌入 python-opencv 的问题(单张图片正常,但在网络摄像头上失败)
- recursion - 替换列表中的匹配项 - Racket
- docker - “docker run -i busybox sh”在 Windows 上因 \r 字符或“:未找到”而失败
- swift - 如何停止导航到另一个视图控制器 swift 5
- javascript - 输入自由文本输入 HTML 时的内联下拉列表选择
- python - 客户用户模型错误;ModuleNotFoundError:没有名为“帐户”的模块