Сбор списка <Long>результатов из RecursiveTask a ForkJoinPool - PullRequest
0 голосов
/ 24 июня 2019

нам нужно разделить вычисление простого множителя на несколько рекурсивных задач в forkjoinpool.

У нас есть список простых чисел и размер рабочей нагрузки, например 5. Поэтому, если мы хотим вычислить простые множители для50, мы получаем все простые числа до 25 и вычисляем простые множители.WorkloadSize - это количество простых чисел, которые будет обрабатывать одна рекурсивная задача.

Что я сделал:

Long[] workLoad = new Long[primes.size()];
workLoad = primes.toArray(workLoad);

pool = new ForkJoinPool();
ForkJoinWorker worker = new ForkJoinWorker(workLoad, q, partitionSize, 0);
pool.execute(worker);

resultList =  worker.invoke();

workLoad = массив всех простых чисел.

q =число, для которого мы хотим вычислить простые множители.

ForkJoinWorker расширяет RecursiveTask>

Внутри рекурсивной задачи я смотрю, больше ли workLoadSize, чем массив простых чисел, которые я получил, если он, Я создаю новый

ForkJoinWorker f = new ForkJoinWorker(..);
f.fork();
List<Long> results = calcFactors(...);
results.addAll(f.join);
return results;

Я только что получил что-то совершенно неправильно?Я всегда получаю параллельное исключение и переполнение стека.Я думаю, что я не соединяю рекурсивные задачи правильно, потому что это всегда вызывает переполнение стека.

1 Ответ

0 голосов
/ 24 июня 2019

Полная трассировка стека и более полный пример кода должны помочь прояснить, что происходит. Но в показанном вами коде выделяются несколько вещей.

Вызов основного задания

В вашем образце вы делаете

pool.execute(worker);
resultList =  worker.invoke();

Это не тот способ, которым он должен работать.

Вызов «execute» отправляет задачу, что нормально, но она не будет ждать ее завершения. Итак, вы только что запустили вычисление без дескриптора при его завершении или результате.

Вызов invoke самостоятельно - это не то, что вы обычно делаете, вы должны позволить pool вызывать сам этот метод. Потому что он начнет выполнение задачи в вызывающем потоке без поддержки какого-либо пула. Так что вы можете даже заблокировать себя, если вы join в нелогичном порядке.

«Предполагаемый» способ вызвать RecursiveTask<T> - позвонить по номеру pool.invoke(task), который вернет вам T (результат вычисления) или pool.submit(task), который вернет вам Future .

Совместное использование состояния между задачами

Этот фрагмент кода внутри задачи может быть проблематичным:

List<Long> results = calcFactors(...);
results.addAll(f.join);

Это будет работать, если calcFactors создаст свой собственный List для возврата. Но если этот список распределяется между задачами, это означает, что несколько задач (и потоков) могут выполнять addAll в одном экземпляре, что будет работать только в том случае, если список сможет его поддерживать (я думаю, что единственный одновременный List в JDK это CopyOnWriteArrayList).

...