스레드 사이에서 계산 작업을 분산하기 위해 jsr166y ForkJoinPool을 사용하고 있습니다. 그러나 나는 틀린 일을 분명히하고 있어야합니다.ForkJoinPool parallelism = 1 deadlock
병렬 처리가 1보다 큰 ForkJoinPool (기본값은 Runtime.availableProcessors()이고 2-8 스레드로 실행 중입니다)을 만들면 내 작업이 완벽하게 작동하는 것 같습니다. 그러나 parallelism = 1 인 ForkJoinPool을 만들면 예기치 않은 반복 횟수가 발생하면 교착 상태가 발생합니다.
예 - 병렬 처리 = 1로 설정하는 것은 이상한 방법입니다. 이 경우, 스레드 수가 증가함에 따라 병렬 알고리즘을 프로파일 링하고 있는데, 병렬 구현의 오버 헤드를 정확하게 확인하기 위해 병렬 직렬 버전을 비교하여 단일 스레드와 함께 실행하여 병렬 직렬 버전을 비교하려고합니다. .
다음은 내가 본 문제를 보여주는 간단한 예입니다. '작업'은 고정 배열의 더미 반복이며, 16 개의 하위 작업으로 반복적으로 나뉘어져 있습니다.
THREADS = 2 (이상)로 실행하면 THREADS = 2 이상으로 실행하면 안정적으로 실행되지만 THREADS = 1로 실행하면 항상 교착 상태가됩니다. 예측할 수없는 반복 횟수가 지나면 main 루프가 ForkJoinPool.invoke()에서 멈추고 task.join()을 기다리고 작업자 스레드가 종료됩니다.
나는 리눅스에서 JDK 1.6.0_21 및 1.6.0_22로 실행하고, jsr166y의 버전을 사용하고 더그 레아의 웹 사이트에서 며칠 전에 다운로드 (http://gee.cs.oswego.edu/dl/concurrency-interest/index.html)
저는 누락 된 것에 대해 어떤 제안 ? 미리 감사드립니다.
package concurrent;
import jsr166y.ForkJoinPool;
import jsr166y.RecursiveAction;
public class TestFjDeadlock {
private final static int[] intArray = new int[256 * 1024];
private final static float[] floatArray = new float[256 * 1024];
private final static int THREADS = 1;
private final static int TASKS = 16;
private final static int ITERATIONS = 10000;
public static void main(String[] args) {
// Initialize the array
for (int i = 0; i < intArray.length; i++) {
intArray[i] = i;
}
ForkJoinPool pool = new ForkJoinPool(THREADS);
// Run through ITERATIONS loops, subdividing the iteration into TASKS F-J subtasks
for (int i = 0; i < ITERATIONS; i++) {
pool.invoke(new RecursiveIterate(0, intArray.length));
}
pool.shutdown();
}
private static class RecursiveIterate extends RecursiveAction {
final int start;
final int end;
public RecursiveIterate(final int start, final int end) {
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if ((end - start) <= (intArray.length/TASKS)) {
// We've reached the subdivision limit - iterate over the arrays
for (int i = start; i < end; i += 3) {
floatArray[i] += i + intArray[i];
}
} else {
// Subdivide and start new tasks
final int mid = (start + end) >>> 1;
invokeAll(new RecursiveIterate(start, mid), new RecursiveIterate(mid, end));
}
}
}
}
디자인대로 작동하는 것 같습니다. 병렬 처리를 1 번 요청하고 있지만 invokeAll에 두 개의 작업을 추가하려고합니다. 그러나 나는 이것에 대한 전문가가 아니므로 잘못되었을 수도 있습니다. –
다른 사람들로부터 전에이 말을 들었습니다. 스레드의 수를 '하나 더'로 설정하면 문제가 해결됩니다. –
Re : Jochen - 프레임 워크를 이해하면서 병렬 처리 수준 (스레드 수)에 관계없이 임의의 수의 작업을 추가 할 수 있어야합니다. 예를 들어, 큰 작업을 반복적으로 256 개의 작은 작업으로 세분 할 수 있지만 256 개 미만의 프로세서가있는 시스템에서이 알고리즘을 실행할 수 있어야합니다. 또한, 교착 상태가 즉각적이지는 않습니다 (예를 들어, 2 개의 작업/1 개의 스레드가 불법 인 경우 예상 할 수있는 것처럼 예측할 수없는 반복 횟수가 반복됩니다.) 그러나 FJ도 비교적 새로운 개념이므로 오해의 소지가 있습니다. – AaronD