eachParallel() генерирует исключение groovy.lang.MissingMethodException при использовании GPars

В настоящее время я пытаюсь использовать GPars для одновременного прохождения системы каталогов в режиме DFS. Это то, что у меня есть до сих пор:

ArrayList<String> visited = Collections.synchronizedList(new ArrayList<String>())

void scheduleDirectory(String rootStartPath) {
    GParsPool.withPool(4) {
        dfs(rootStartPath)
    }
}

void dfs(String path) {
    visited << path

    // This will retrieve what's in the path directory
    // Each object inside listResult shows the name, path, type (directory or file), etc.
    def listResult = dao.listDirectory(tenant, namespace, path)
    if(listResult) {
        listResult.eachParallel {
            def childPath = getPath(it)   // Get the path of the listResult
            if(it.type == "directory") {
                if(!visited.contains(childPath)) {
                    dfs(childPath)
                }
            }
            else if(it.type == "object") {
                // Do some other processing stuff
            }
        }
    }
}

Но когда я пытаюсь вызвать eachParallel() с замыканием, я получаю это в своей трассировке стека:

groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.eachParallel() is applicable for argument types: (com.abc.service.DFSService$_dfs_closure2) values: [com.abc.service.DFSService$_dfs_closure2@7d016471]
        at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:72) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:48) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127) ~[groovy-2.5.4.jar:2.5.4]
        at com.abc.service.DFSService.dfs(DFSService.groovy:86) ~[main/:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_212]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_212]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:104) ~[groovy-2.5.4.jar:2.5.4]
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:326) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:352) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:68) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:156) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:168) ~[groovy-2.5.4.jar:2.5.4]
        at com.abc.service.DFSService$_dfs_closure2.doCall(DFSService.groovy:97) ~[main/:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_212]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_212]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_212]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_212]
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:104) ~[groovy-2.5.4.jar:2.5.4]
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:326) ~[groovy-2.5.4.jar:2.5.4]
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264) ~[groovy-2.5.4.jar:2.5.4]
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041) ~[groovy-2.5.4.jar:2.5.4]
        at groovy.lang.Closure.call(Closure.java:411) ~[groovy-2.5.4.jar:2.5.4]
        at groovy.lang.Closure.call(Closure.java:427) ~[groovy-2.5.4.jar:2.5.4]
        at groovyx.gpars.pa.CallClosure.call(CallClosure.java:47) ~[gpars-1.2.1.jar:1.2.1]
        at groovyx.gpars.pa.ClosureMapper.op(ClosureMapper.java:36) ~[gpars-1.2.1.jar:1.2.1]
        at groovyx.gpars.extra166y.AbstractParallelAnyArray$OOMPap.leafTransfer(AbstractParallelAnyArray.java:2255) ~[gpars-1.2.1.jar:1.2.1]
        at groovyx.gpars.extra166y.PAS$FJOMap.atLeaf(PAS.java:258) ~[gpars-1.2.1.jar:1.2.1]
        at groovyx.gpars.extra166y.PAS$FJBase.internalCompute(PAS.java:118) ~[gpars-1.2.1.jar:1.2.1]
        at groovyx.gpars.extra166y.PAS$FJBase.compute(PAS.java:106) ~[gpars-1.2.1.jar:1.2.1]
        at jsr166y.RecursiveAction.exec(RecursiveAction.java:148) ~[jsr166y-1.7.0.jar:1.7.0]
        at jsr166y.ForkJoinTask.doExec(ForkJoinTask.java:305) ~[jsr166y-1.7.0.jar:1.7.0]
        at jsr166y.ForkJoinWorkerThread.execTask(ForkJoinWorkerThread.java:575) ~[jsr166y-1.7.0.jar:1.7.0]
        at jsr166y.ForkJoinPool.scan(ForkJoinPool.java:755) ~[jsr166y-1.7.0.jar:1.7.0]
        at jsr166y.ForkJoinPool.work(ForkJoinPool.java:617) ~[jsr166y-1.7.0.jar:1.7.0]
        at jsr166y.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:369) ~[jsr166y-1.7.0.jar:1.7.0]

Я уже видел этот вопрос, поэтому я подумал, что, может быть, это мой build.gradle, но это тоже не так. Мой файл gradle.build:

...
dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.5.4',
            'org.codehaus.gpars:gpars:1.2.1'
            ...
    }
...

person sparkhee93    schedule 30.09.2019    source источник
comment
Что произойдет, если вы используете только each?   -  person chrylis -cautiouslyoptimistic-    schedule 01.10.2019
comment
@chrylis Он работает нормально, но смысл в том, чтобы запускать его параллельно из-за производительности.   -  person sparkhee93    schedule 01.10.2019
comment
Я так понимаю, вы хотите запустить его параллельно. Я спрашиваю в качестве шага отладки, потому что вы не упомянули, была ли у вас все еще ошибка.   -  person chrylis -cautiouslyoptimistic-    schedule 01.10.2019
comment
Какую версию Java вы используете? Если 9 или выше, импортировали ли вы модуль, а также зависимость?   -  person chrylis -cautiouslyoptimistic-    schedule 01.10.2019
comment
Я получаю сообщение об ошибке, но это исключение com.amazonaws.SdkClientException, которое, как мне кажется, связано с моим подключением к VPN. Но кроме этого, он работает нормально. Я использую Java 8.   -  person sparkhee93    schedule 01.10.2019


Ответы (1)


Похоже, что размещение GParsPool.withPool() вне метода dfs приведет к тому, что рекурсивные вызовы dfs выйдут за рамки GPars, и в результате listResult во вложенных вызовах не будет доступен метод eachParallel().

Ваша проблема устранена, если вы переместите закрытие GParsPool.withPool(4) в метод dfs, и результаты будут выполняться параллельно, ограничено 4 потоками, как и ожидалось:

ArrayList<String> visited = Collections.synchronizedList(new ArrayList<String>())

void scheduleDirectory(String rootStartPath) {
    dfs(rootStartPath)
}

void dfs(String path) {
    GParsPool.withPool(4) {
        visited << path

        // This will retrieve what's in the path directory
        // Each object inside listResult shows the name, path, type (directory or file), etc.
        def listResult = dao.listDirectory(tenant, namespace, path)
        if(listResult) {
            listResult.eachParallel {
                def childPath = getPath(it)   // Get the path of the listResult
                if(it.type == "directory") {
                    if(!visited.contains(childPath)) {
                        dfs(childPath)
                    }
                }
                else if(it.type == "object") {
                    // Do some other processing stuff
                }
            }
        }
    }
}
person pczeus    schedule 25.04.2020