我正在尝试在 grails 中使用执行器插件,但遇到了一个无法解决的问题。 基本上,我有一个要抓取的链接列表,但遇到的问题是它总是抓取相同的链接,因此我将示例简化为:
List offerLinks = getOfferLinks(parser)
offerLinks.each{println it}
List futures = new Vector()
for (def link : offerLinks) {
def future = callAsync {
return link
}
futures.add(future)
}
futures.each{println "FUTURE " + it.get()}
这是控制台中打印的内容
bt-ofrd-acciona-6633344.htm?
bt-ofrd-celiasiffredi-293068.htm?
bt-ofrd-clahubiz-92924.htm?
bt-ofrd-haruko-1672632.htm?
future bt-ofrd-clahubiz-92924.htm?
future bt-ofrd-haruko-1672632.htm?
future bt-ofrd-haruko-1672632.htm?
future bt-ofrd-haruko-1672632.htm?
前 4 个结果针对 offerLinks.each{println it}
代码
最后 4 个用于 futures.each{println "FUTURE "+ it.get()}
我试图找出的是为什么将这些链接放入 callAsync block 并从 future 对象中检索它们会使它们采用最后一个值,看起来它会替换已经创建的 future 对象?
这段代码位于 Controller 调用的服务内部。 我很感激你能给我的任何帮助。谢谢
更新:
我认为 Java 执行器 API 中存在某种问题......或者也许我不完全理解它的真正工作原理?
这是另一个测试,更改代码以使用 invokeAll:
def threadPool = Executors.newCachedThreadPool()
List offerLinks = getOfferLinks(parser)
List lista = new ArrayList()
for (enlace in offerLinks) {
println "link " + enlace
lista.add({enlace} as Callable)
}
def futures = threadPool.invokeAll(lista)
futures.each{println "FUTURE " + it.get()}
这就是打印的内容
链接/bt-ofrd-implementar-192996.htm?
链接/bt-ofrd-cdonini-864908.htm?
链接/bt-ofrd-hvtalent-1493932.htm?
链接/bt-ofrd-dbak-1358120.htm?
链接/bt-ofrd-hexacta-100072.htm?
链接/bt-ofrd-ccibelli-457472.htm?
future /bt-ofrd-ccibelli-457472.htm?
future /bt-ofrd-ccibelli-457472.htm?
future /bt-ofrd-ccibelli-457472.htm?
future /bt-ofrd-ccibelli-457472.htm?
future /bt-ofrd-ccibelli-457472.htm?
future /bt-ofrd-ccibelli-457472.htm?
最佳答案
在我看来,在闭包外部定义的变量范围发生了一些奇怪的事情,但从内部引用,它没有正确“关闭”。如果这样做的话效果会更好吗
def threadPool = Executors.newCachedThreadPool()
List offerLinks = getOfferLinks(parser)
List lista = new ArrayList()
for (enlace in offerLinks) {
println "link " + enlace
lista.add(({ it }.curry(enlace)) as Callable)
}
def futures = threadPool.invokeAll(lista)
futures.each{println "FUTURE " + it.get()}
这应该确保正确的东西被传递到闭包中,并且闭包本身不需要直接引用外部定义的enlace
变量。
这本身并不能解释为什么您已经尝试过的方法不起作用,但它可能会为您提供解决方法。
编辑:我以前没有发现这一点,但我现在注意到您没有在 for
循环中声明 enlace
,因此它不是局部变量,并且闭包(正确地)引用单个共享变量,而不是“关闭”特定循环迭代中的值。如果您使用这样的结构,它应该可以工作:
def tasks = offerLinks.collect { link ->
println "link " + enlace
return ({ link } as Callable)
}
def futures = threadPool.invokeAll(tasks)
futures.each{println "FUTURE " + it.get()}
其中 link
变量是 collect
闭包的本地变量,因此 {...} as Callable
将在正确的值上关闭。 callAsync
的等效方法是使用
List futures = offerLinks.collect { link ->
callAsync { link }
}
关于Grails 执行器插件 callAsync block 始终采用相同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15302909/