Grails 异步 Promise/for 循环错误 - 如何将变量传递给任务闭包

标签 grails for-loop closures promise

我有许多文件需要解析,因此我通过多个线程执行此操作。

int fileCount = 16
def promiseList = []
for (int i = 1; i <= fileCount; i++) {
    println i
    def p = task {
        println "${new Date()} Starting parse of schedules (${i})..."
        // do some parsing here, where I need access to the value i     
    }
    p.onError {Throwable t ->
        println "Serious error when loading schedule ${i}, ${t.getMessage()}"
        t.printStackTrace()
    }
    promiseList << p
}
waitAll(promiseList)

这里的想法是创建多个 Promise,将它们设置为异步运行,然后让它们全部完成。

Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (1)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (3)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (4)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (5)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (6)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (7)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (8)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (9)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (10)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (11)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (13)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (12)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (14)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (15)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (16)...
Wed Feb 25 16:36:36 GMT 2015 Starting parse of schedules (17)...

问题:2 号任务到底发生了什么?如果我输入:

println i

进入for循环,然后一切都如预期(即我得到1..16)。我认为变量正在被递增,然后在稍后的某个时刻,闭包查看该变量并且它已经被递增,因此值不正确。如何将值 i 传递给闭包以便获得正确的值?

编辑:对于它的值(value),我可以通过插入来破解它,我真的不喜欢这样做:

// for ()
    int taskNumber = i
    // create task here, refer to local variable taskNumber instead of i
    Thread.currentThread().sleep((long)(1000))

在for循环的末尾,以便在下一个循环发生之前正确实例化任务。然而,这是一个非常令人讨厌的黑客行为,我确信一定有更好的方法将变量传递给线程?

进一步编辑:

这是我使用以下方法实现 for 循环时的输出:

for (i in 1..fileCount)

Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (1)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (3)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (4)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (5)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (6)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (8)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (7)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (9)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (11)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (13)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (13)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (13)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (14)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (15)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (16)...
Wed Feb 25 16:57:54 GMT 2015 Starting parse of schedules (16)...

最佳答案

i 在当前所有闭包/任务之间共享。在创建闭包期间,您需要将 i 的副本从当前上下文/当前线程传递到闭包本身。您可以使用柯里化(Currying)来做到这一点,例如:

def p = task({int locali -> 
    println "${new Date()} Starting parse of schedules (${locali})..."
    // do some parsing here, where I need access to the value i     
}.curry(i))
p.onError({int locali, Throwable t ->
    println "Serious error when loading schedule ${locali}, ${t.getMessage()}"
    t.printStackTrace()
}.curry(i))

另一种方法是从不同的上下文创建闭包(更多Java方式,基本上就是你用collect hack所做的):

Closure createTask(final int i) {
  return {
    println "${new Date()} Starting parse of schedules (${i})..."
    // do some parsing here, where I need access to the value i     
  }
}

然后:

def p = task(createTask(i))

关于Grails 异步 Promise/for 循环错误 - 如何将变量传递给任务闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28724871/

相关文章:

grails - Grails中的Quartz Scheduler

unit-testing - Grails 单元测试无法识别域类上的 .save()

python - 关于在python中迭代函数的问题

xcode - Swift - 闭包表达式语法

objective-c - 将 Swift 2 闭包转换为 Objective-C block

web-services - 将 Grails 应用程序拆分为 Web 服务和演示文稿的最佳方法是什么?

Grails 使用 gstring 访问嵌套字段

c++ - 数组中的重复数字

if 语句中的 javascript 迭代

closures - 在结构中存储闭包——无法推断出合适的生命周期