https://github.com/BanditBool2/ReadingRecord/issues/38
생각보다 간단한 내용이었다. 재사용의 의미가 진짜 말 그대로 재사용이었다.
포크조인 프레임워크는 서브태스크를 스레드 풀의 작업자 스레드 에 분산 할당하는 ExecutorService인터페이스를 구현한다.
compute()를 구현해야함.
Divide&Conquer의 병렬화버전으로 보면 된다.
분할
ForkJoinSumClculator를 ForkJoinPool로 전달하면, 풀의 스레드가 ForkJoinSumCalculator의 compute()를 실행하면서 작업을 수행한다.
이 과정이 조건(수행 항목이 만개 이상)을 만족할때까지 재귀적으로 반복하며 태스크 분할
두 서브태스크가 모두 시작된 다음 join을 호출해야 한다.
a. join메서드를 태스크에 호출하면 태스크가 생산하는 결과가 준비될 때까지 호출자를 블록시키기 때문.
RecursiveTask 내에서는 ForkJoinPool의 invoke()를 사용하지 말아야 한다.
a. 대신 compute()나 fork()를 직접 호출 가능
b. 순차 코드에서 병렬 계산 시작시에만 invoke() 사용
둘 다 fork()를 호출 하는 것 보다 한쪽에는 compute()를 호출하는 것이 효율적이다.
a. fork() 메서드를 호출해서 ForkJoinPool의 일정을 조절할 수 있다.
b. 한 태스크에는 같은 스레드를 재사용 할 수 있으므로 풀에서 불필요한 태스크 할당을 피할 수 있다.
디버깅이 어렵다. stack trace가 도움이 되지 않는다.
a. 한 쪽에는 fork, 다른 하나는 compute가 호출 되므로
멀티코어에 포크/조인 프레임워크 사용이 순차 처리보다 무조건 빠를거라는 생각은 버려라.
a. 각 태스크의 실행시간이 포킹하는데 드는 시간보다 길어야 한다.
b. 또한 컴파일러 최적화는 병렬 버전보다는 순차 버전에 집중될 수 있다는 사실도 기억