【问题标题】:Currying groovy CPS closure for parallel execution用于并行执行的 Currying groovy CPS 闭包
【发布时间】:2017-01-19 14:31:33
【问题描述】:

我们在某些工作中动态创建并行步骤。感谢this thread,我找到了如何使用参数动态创建地图以在并行步骤中使用。

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

但是,currying 似乎无法正常工作。在闭包内引用循环变量 (valueCopy) 是正确的 (as mentioned here),但柯里化并没有达到我的预期。

我是不是做错了什么,这只是(尚)不支持吗,有什么解决方法吗?这可能是 Jenkins 管道中的错误吗?

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

Jenkins:LTS (2.32.1) 和截至 2017/01/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

【问题讨论】:

    标签: jenkins parallel-processing closures jenkins-pipeline currying


    【解决方案1】:

    我不确定是柯里化还是 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 风格”循环,你就需要将你的函数标记为 NonCPS。

    【讨论】:

    • 感谢您的回答。由于某种原因,我没有收到通知:(。我会尽快尝试。
    • 标记为已解决,因为这确实解决了我的问题。不幸的是,我没有提到我当然想在并行闭包中使用 CPS 代码:(
    【解决方案2】:

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

    他们已经评论了他们的例子

    // 每次迭代的新变量;我会变异

    我认为使用 C 风格的循环不会消除这个限制,并且柯里化(这个用例需要)也不能解决这个问题。笨拙,但很容易解决。

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2016-04-16
        • 2010-10-20
        • 1970-01-01
        • 1970-01-01
        • 2021-07-23
        • 1970-01-01
        • 1970-01-01
        • 2017-08-01
        • 1970-01-01
        相关资源
        最近更新 更多