使用柯里化处理 Groovy CPS 闭包以实现并行执行

10

我们在一些工作中进行动态创建并行步骤。感谢这个帖子,我找到了如何动态创建具有参数映射以在并行步骤中使用的方法。

但是现在我想重用用于创建这些并行步骤的代码的某些部分。为此,我觉得我需要对闭包进行柯里化。

然而,柯里化似乎不能正常工作。在闭包内引用循环变量(valueCopy)会做正确的事情(如此提到),但柯里化不会像我期望的那样工作。

我做错了什么吗?这只是不受支持的(尚未支持)吗?有没有解决办法?这可能是 Jenkins Pipeline 中的一个 bug 吗?

希望有人知道为什么这不起作用和/或如何使其起作用。

Jenkins 版本:LTS (2.32.1) 和截至 2017/01/19 的最新插件更新。

解决方案:

升级到 Pipeline: Groovy 插件版本 2.40 后,一切都按预期工作了。

执行的 Pipeline 脚本:

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
3个回答

5
我不确定是因为柯里化还是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。


谢谢回答。不知何故我没有收到通知 :( 。我会尽快尝试一下。 - Joerg S
标记为已解决,因为这确实解决了我的问题。不幸的是,我忘了提到我当然想在并行闭包中使用 CPS 代码 :( - Joerg S

0

这似乎是Groovy语言或Jenkins Groovy运行时的限制,我不确定哪个,但值得注意的是,他们的示例与您所做的完全相同,为循环的每次迭代声明一个新变量。

他们已经对他们的示例进行了评论

//每次迭代都有新变量;i将被改变

我认为使用C风格的循环不会消除这种限制,而柯里化(在这种情况下需要)也无法解决问题。虽然笨拙,但足够容易解决。

https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#creating-multiple-threads


0
发现最新的Pipeline: Groovy插件(2.40)与至少Jenkins版本2.60.3结合使用时,一切都按预期工作(尽管插件主页声明需要至少Jenkins 2.73.3)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接