Потоки Gpars.withPool в конечном итоге перестают выполняться после многократного повторения

Пытался выполнить параллельные операции с Gpars.

Gpars.withPool(6) {
  someList.eachParallel {
    println "${Thread.currentThread}"
  }
}

Изначально похоже на работу

Thread[ForkJoinPool-1-worker-1,5,main] 
Thread[ForkJoinPool-1-worker-6,5,main] 
Thread[ForkJoinPool-1-worker-2,5,main]  
Thread[ForkJoinPool-1-worker-5,5,main] 
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-4,5,main] 
Thread[ForkJoinPool-1-worker-1,5,main]
Thread[ForkJoinPool-1-worker-6,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]

Но после некоторого повторения некоторые потоки перестают выполняться.

Thread[ForkJoinPool-1-worker-2,5,main]
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]
Thread[ForkJoinPool-1-worker-3,5,main] 
Thread[ForkJoinPool-1-worker-2,5,main] 
Thread[ForkJoinPool-1-worker-3,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]

До тех пор, пока в итоге мы не останемся с одним.

Thread[ForkJoinPool-1-worker-2,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]
Thread[ForkJoinPool-1-worker-2,5,main]

Есть идеи, почему это происходит? Любое решение, чтобы сохранить все потоки активными?

В моем случае, возможно, стоит упомянуть, что мы выполняем итерацию в диапазоне 50–200 тыс.

1 ответ

Решение

На всякий случай у других людей такая же проблема. Их документация гласит:

Поскольку GParsPool использует пул Fork/Join (с перехватом работы), потоки не могут быть применены к задаче ожидающей обработки, даже если они могут показаться неактивными. С помощью алгоритма кражи рабочих потоков рабочие потоки, у которых заканчивается работа, могут красть задачи из других потоков, которые все еще заняты.

если вы используете GParsExecutorsPool, который не использует Fork/Join, вы получите поведение распределения потоков, которое вы наивно ожидаете.

Исходя из этого, я предпочитаю использовать GParsExecutorsPool вместо этого. При этом все потоки выполняются последовательно до конца всего процесса каждого параллельного процесса.

GParsExecutorsPool.withPool(6) {
  someList.eachParallel {
    println "${Thread.currentThread}"
  }
}
Другие вопросы по тегам