Currying groovy CPS 闭包用于并行执行
Currying groovy CPS closure for parallel execution
我们在一些工作中动态创建并行步骤。多亏了 ,我找到了如何使用参数动态创建地图以用于并行步骤。
但是现在我想重用用于创建这些并行步骤的部分代码。为此,我觉得我需要对闭包进行 curry。
然而柯里化似乎无法正常工作。在闭包中引用循环变量 (valueCopy) 是正确的 (),但柯里化并没有达到我的预期。
我是不是做错了什么,这是否(尚)不受支持,是否有任何解决方法?这可能是 Jenkins 管道中的错误吗?
希望有人知道为什么这不起作用and/or如何让它起作用。
Jenkins:LTS (2.32.1) 和截至 2017 年 1 月 19 日的最新插件更新。
解决方案:
升级到 Pipeline 后:Groovy 插件版本 2.40 现在一切正常。
执行的管道脚本:
def echoSome(val) {
echo val
}
def buildClosures() {
def someList = ["1", "2", "3"]
def closures = [:]
for (value in someList) {
final valueCopy = value
closures[value] = {val ->
echo valueCopy.toString()
echo val.toString()
}.curry(value)
}
closures
}
parallel buildClosures()
输出:
[Pipeline] parallel
[Pipeline] [1] { (Branch: 1)
[Pipeline] [2] { (Branch: 2)
[Pipeline] [3] { (Branch: 3)
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] echo
[1] 3
[Pipeline] [1] }
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] echo
[2] 3
[Pipeline] [2] }
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] }
[Pipeline] // parallel
[Pipeline] End of Pipeline
Finished: SUCCESS
预期输出:
[Pipeline] parallel
[Pipeline] [1] { (Branch: 1)
[Pipeline] [2] { (Branch: 2)
[Pipeline] [3] { (Branch: 3)
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] }
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] }
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] }
[Pipeline] // parallel
[Pipeline] End of Pipeline
Finished: SUCCESS
我不确定是柯里化还是 for 循环,但此函数需要标记为 NonCPS,如下所述:https://github.com/jenkinsci/pipeline-examples/blob/master/docs/BEST_PRACTICES.md#groovy-gotchas
基本上,这样做:
@NonCPS
def buildClosures() {
def someList = ["1", "2", "3"]
def closures = [:]
for (value in someList) {
final valueCopy = value
closures[value] = {val ->
echo valueCopy.toString()
echo val.toString()
}.curry(value)
}
closures
}
我认为这是您的 for 循环,但无论如何,无论何时您不使用经典 "C Style" 循环,您都需要将您的函数标记为 NonCPS。
这似乎是 Groovy 语言或 Jenkins groovy 运行时的限制,我不确定是哪个,但值得注意的是他们的示例与您所做的完全一样,为循环的每次迭代声明一个新变量。
他们评论了他们的例子
// fresh variable per iteration; i will be mutated
我认为使用 C 风格的循环不会消除此限制,柯里化(此用例需要)也无法解决问题。笨拙,但很容易变通。
https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#creating-multiple-threads
发现最新的 Pipeline: Groovy 插件 (2.40) 与至少 Jenkins 版本 2.60.3 结合使用(虽然插件主页声明您至少需要 Jenkins 2.73.3)一切正常预期。
我们在一些工作中动态创建并行步骤。多亏了
但是现在我想重用用于创建这些并行步骤的部分代码。为此,我觉得我需要对闭包进行 curry。
然而柯里化似乎无法正常工作。在闭包中引用循环变量 (valueCopy) 是正确的 (
我是不是做错了什么,这是否(尚)不受支持,是否有任何解决方法?这可能是 Jenkins 管道中的错误吗?
希望有人知道为什么这不起作用and/or如何让它起作用。
Jenkins:LTS (2.32.1) 和截至 2017 年 1 月 19 日的最新插件更新。
解决方案:
升级到 Pipeline 后:Groovy 插件版本 2.40 现在一切正常。
执行的管道脚本:
def echoSome(val) {
echo val
}
def buildClosures() {
def someList = ["1", "2", "3"]
def closures = [:]
for (value in someList) {
final valueCopy = value
closures[value] = {val ->
echo valueCopy.toString()
echo val.toString()
}.curry(value)
}
closures
}
parallel buildClosures()
输出:
[Pipeline] parallel
[Pipeline] [1] { (Branch: 1)
[Pipeline] [2] { (Branch: 2)
[Pipeline] [3] { (Branch: 3)
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] echo
[1] 3
[Pipeline] [1] }
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] echo
[2] 3
[Pipeline] [2] }
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] }
[Pipeline] // parallel
[Pipeline] End of Pipeline
Finished: SUCCESS
预期输出:
[Pipeline] parallel
[Pipeline] [1] { (Branch: 1)
[Pipeline] [2] { (Branch: 2)
[Pipeline] [3] { (Branch: 3)
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] echo
[1] 1
[Pipeline] [1] }
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] echo
[2] 2
[Pipeline] [2] }
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] echo
[3] 3
[Pipeline] [3] }
[Pipeline] // parallel
[Pipeline] End of Pipeline
Finished: SUCCESS
我不确定是柯里化还是 for 循环,但此函数需要标记为 NonCPS,如下所述:https://github.com/jenkinsci/pipeline-examples/blob/master/docs/BEST_PRACTICES.md#groovy-gotchas
基本上,这样做:
@NonCPS
def buildClosures() {
def someList = ["1", "2", "3"]
def closures = [:]
for (value in someList) {
final valueCopy = value
closures[value] = {val ->
echo valueCopy.toString()
echo val.toString()
}.curry(value)
}
closures
}
我认为这是您的 for 循环,但无论如何,无论何时您不使用经典 "C Style" 循环,您都需要将您的函数标记为 NonCPS。
这似乎是 Groovy 语言或 Jenkins groovy 运行时的限制,我不确定是哪个,但值得注意的是他们的示例与您所做的完全一样,为循环的每次迭代声明一个新变量。
他们评论了他们的例子
// fresh variable per iteration; i will be mutated
我认为使用 C 风格的循环不会消除此限制,柯里化(此用例需要)也无法解决问题。笨拙,但很容易变通。
https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#creating-multiple-threads
发现最新的 Pipeline: Groovy 插件 (2.40) 与至少 Jenkins 版本 2.60.3 结合使用(虽然插件主页声明您至少需要 Jenkins 2.73.3)一切正常预期。