Serialization Groovy中闭包的保存状态

Serialization Groovy中闭包的保存状态,serialization,groovy,closures,Serialization,Groovy,Closures,我想使用Groovy闭包来处理来自SQL表的数据。对于每一个新行,计算将取决于以前计算的内容。但是,在应用程序的进一步运行中,新行可能会变得可用,因此我希望能够重新加载闭包,并使用上次在应用程序的上一次运行中执行闭包时的中间状态进行初始化 例如,打算计算3行移动平均数的闭包将如下实现: def prev2Val = null def prevVal = null def prevId = null Closure c = { row -> println([ prev2Val,

我想使用Groovy闭包来处理来自SQL表的数据。对于每一个新行,计算将取决于以前计算的内容。但是,在应用程序的进一步运行中,新行可能会变得可用,因此我希望能够重新加载闭包,并使用上次在应用程序的上一次运行中执行闭包时的中间状态进行初始化

例如,打算计算3行移动平均数的闭包将如下实现:

def prev2Val = null
def prevVal = null
def prevId = null

Closure c = { row ->
    println([ prev2Val, prevVal, prevId])

    def latestVal = row['val']

    if (prev2Val != null) {
        def movMean = (prev2Val + prevVal + latestVal) / 3
        sql.execute("INSERT INTO output(id, val) VALUES (?, ?)", [prevId, movMean])
    }

    sql.execute("UPDATE test_data SET processed=TRUE WHERE id=?", [row['id']])

    prev2Val = prevVal
    prevVal = latestVal
    prevId = row['id']
}
sql.eachRow("SELECT id, val FROM test_data WHERE processed=FALSE ORDER BY id", c)
test\u data
有3列:
id
(自动递增主键)、
已处理
。根据前两个值计算移动平均值,并对照前一行的
id
插入
output
表格。已处理的行标记为
Processed=TRUE

如果从一开始所有数据都可用,可以这样称呼:

def prev2Val = null
def prevVal = null
def prevId = null

Closure c = { row ->
    println([ prev2Val, prevVal, prevId])

    def latestVal = row['val']

    if (prev2Val != null) {
        def movMean = (prev2Val + prevVal + latestVal) / 3
        sql.execute("INSERT INTO output(id, val) VALUES (?, ?)", [prevId, movMean])
    }

    sql.execute("UPDATE test_data SET processed=TRUE WHERE id=?", [row['id']])

    prev2Val = prevVal
    prevVal = latestVal
    prevId = row['id']
}
sql.eachRow("SELECT id, val FROM test_data WHERE processed=FALSE ORDER BY id", c)
当应用程序运行后新行变为可用时,问题就会出现。这可以通过每次处理一小批来模拟(例如,在前面的语句中使用
LIMIT 5

我希望能够在每次执行
结束时转储闭包的完整状态(例如将中间数据保存在数据库中的某个位置),并在重新运行整个应用程序时重新初始化它(通过从数据库加载这些中间变量)

在这个特定的示例中,我可以通过存储
prev2Val
prevVal
prevId
的值来手动执行此操作,但我正在寻找一种通用解决方案,在这种解决方案中,不必确切知道使用了哪些变量

可能类似于
c.getState()
,它将在下次执行应用程序时返回
[prev2Val:1,prevVal:2,prevId:6]
(例如),并且我可以在其中使用c.setState(
[prev2Val:1,prevVal:2,prevId:6]

我还需要从列表中排除
sql
。这似乎可以使用
c.@sql=null
来完成

我意识到这在一般情况下不太可能起作用,但我正在寻找一种对大多数情况都足够通用的方法。如中所述,我已尝试对闭包进行脱水、序列化和再水化,但我不确定如何在一次操作中保存和存储所有
@
字段


这可能吗?假设闭包使用的变量列表不一定事先知道,有没有更好的方法来记住执行之间的状态?

不确定这在长期内是否有效,您最好返回一个列表,其中包含要传递给闭包以获取下一组数据的值,但是你可以询问闭包的绑定

鉴于:

def closure = { row ->
  a = 1
  b = 2
  c = 4
}
如果您执行它:

closure( 1 )
然后,您可以编写如下函数:

def extractVarsFromClosure( Closure cl ) {
  cl.binding.variables.findAll { 
    !it.key.startsWith( '_' ) && it.key != 'args'
  }
}
执行时:

println extractVarsFromClosure( closure )
印刷品:

['a':1, 'b':2, 'c':4]
但是,在本地绑定中定义的任何“自由”变量(不带
def
)也将在闭包绑定中,因此:

fish = 42
println extractVarsFromClosure( closure )
将打印:

['a':1, 'b':2, 'c':4, 'fish':42]
但是


不会打印值
fish

,这正是我所期望的问题。此外,闭包似乎没有绑定,除非我事先明确地给它一个委托(在下面的部分中)。不管怎么说,这正是我想要做的。干杯