2

grailsでexecutorプラグインを使用しようとしていますが、解決できない問題が発生しています。基本的に、クロールしたいリンクのリストがあり、常に同じリンクをクロールするという問題が発生したため、例を次のように簡略化しました。

    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?
将来のbt-ofrd-clahubiz-92924.htm?
将来のbt-ofrd-haruko-1672632.htm?
将来のbt-ofrd-haruko-1672632.htm?
将来のbt-ofrd-haruko-1672632.htm?

最初の4つの結果はofferLinks.each{println it}コード用です
最後の4つはfutures.each{println "FUTURE " + it.get()}

私が見つけようとしているのは、これらのリンクをcallAsyncブロックに入れて、将来のオブジェクトから取得すると、最後の値を取得する理由です。すでに作成されている将来のオブジェクトを置き換えるように見えますか?

このコードは、コントローラーによって呼び出されるサービス内にあります。私はあなたが私に与えることができるどんな助けにも感謝します。ありがとう

更新
Java executor 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?
将来/bt-ofrd-ccibelli-457472.htm?
将来/bt-ofrd-ccibelli-457472.htm?
将来/bt-ofrd-ccibelli-457472.htm?
将来/bt-ofrd-ccibelli-457472.htm?
将来/bt-ofrd-ccibelli-457472.htm?
将来/bt-ofrd-ccibelli-457472.htm?

4

3 に答える 3

2

クロージャーの外側で定義されているが内側から参照されている変数のスコープで何か奇妙なことが起こっているように見えますが、それは適切に「クローズ」されていません。あなたがするならそれはもっとうまくいくでしょうか

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これにより、正しいものがクロージャに渡され、クロージャ自体が外部で定義された変数を直接参照する必要がなくなります。

これだけでは、すでに試したことがうまくいかなかった理由を説明することはできませんが、回避策が得られる可能性があります。


編集:私は以前にこれを見つけませんでしたが、あなたがそのループで宣言 していないことに気付きました。したがって、それはローカル変数ではなく、クロージャは(正しく)単一の共有変数を参照しており、特定のループ反復の値。代わりに次のような構造を使用すると機能するはずです。enlacefor

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 }
}
于 2013-03-11T17:51:18.777 に答える
0

これは良いですか?

List offerLinks = getOfferLinks(parser)
offerLinks.each{println it}

List futures = new Vector()
for (def link : offerLinks) {
    futures.add( callAsync {
        return link
    }

)}

futures.each{println "FUTURE " +  it.get()}
于 2013-03-08T20:52:19.637 に答える
0

私が今経験したのと同じフェノネモンのように聞こえます、この答えを見てください。

私にとっての問題は、「現在のスレッドのMDCが新しく生成されたスレッドに継承される」ということでした。その理由がわからないので、なぜ同じ問題にぶつかるのかわかりませんが、サービスからリンクを取得したためかもしれません。

于 2013-03-09T06:34:20.110 に答える