๐ฆ chap7. ๋ณ๋ ฌ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ฑ๋ฅ
chap7. ๋ณ๋ ฌ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ฑ๋ฅ
7.1 ๋ณ๋ ฌ ์คํธ๋ฆผ
์ปฌ๋ ์
์ parallelStream ์ ํธ์ถํ๋ฉด ๋ณ๋ ฌ ์คํธ๋ฆผ์ด ์์ฑ๋๋ค.
์ด๋ ๊ฐ๊ฐ์ ์ค๋ ๋์์ ์ฒ๋ฆฌํ ์ ์๋๋ก ์คํธ๋ฆผ ์์๋ฅผ ์ฌ๋ฌ ์ฒญํฌ๋ก ๋ถํ ํ ์คํธ๋ฆผ์ด๋ค.
์ซ์ n ์ ์ธ์๋ก ๋ฐ์์ 1๋ถํฐ n๊น์ง์ ๋ชจ๋ ์ซ์์ ํฉ๊ณ๋ฅผ ๋ฐํํ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํด๋ณด์.
1
2
3
4
5
public long sequentialSum(long n) {
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.reduce(0L, Long::sum);
}
์ ํต์ ์ธ JAVA ์์๋ ๋ฐ๋ณต๋ฌธ์ผ๋ก ๊ตฌํํ ์ ์๋ค.
1
2
3
4
5
6
7
public long iterativeSum(long n) {
long result = 0;
for (long i = 1L; i <= n; i++) {
result += i;
}
return result;
}
n ์ด ์ปค์ง๋ค๋ฉด ์ด ์ฐ์ฐ์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ด ์ข์ ๊ฒ์ด๋ค.
7.1.1 ์์ฐจ ์คํธ๋ฆผ์ ๋ณ๋ ฌ ์คํธ๋ฆผ์ผ๋ก ๋ณํํ๊ธฐ
์์ฐจ ์คํธ๋ฆผ์ parallel ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด ๊ธฐ์กด์ ํจ์ํ ๋ฆฌ๋์ฑ ์ฐ์ฐ์ด ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌ๋๋ค.
1
2
3
4
5
6
public long parallelSum(long n) {
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.parallel()
.reduce(0L, Long::sum);
}
์์ฐจ ์คํธ๋ฆผ์ parallel ์ ํธ์ถํด๋ ์คํธ๋ฆผ ์์ฒด๋ ์๋ฌด ๋ณํ๋ ์ผ์ด๋์ง ์์ง๋ง,
๋ด๋ถ์ ์ผ๋ก๋ ์ดํ ์ฐ์ฐ์ด ๋ณ๋ ฌ๋ก ์ํํด์ผ ํจ์ ์๋ฏธํ๋ boolean ํ๋๊ทธ๊ฐ ์ค์ ๋๋ค.
๋ฐ๋๋ก sequential ๋ก ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์์ฐจ ์คํธ๋ฆผ์ ๋ฐ๊ฟ ์ ์๋๋ฐ ์ด ๋ ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์ ์ดํ ์ ์๋ค.
1
2
3
4
5
6
stream.parallel()
.filter(...)
.sequential()
.map(...)
.parallel()
.reduce(...)
parallel ๊ณผ sequential ์ค ๋ง์ง๋ง์ ํธ์ถ๋ ๋ฉ์๋๊ฐ ์ ์ฒด ํ์ดํ๋ผ์ธ์ ์ํฅ์ ๋ฏธ์น๋ค.
์ฌ๊ธฐ์์๋ parallel ์ด๋ฏ๋ก ํ์ดํ๋ผ์ธ์ ์ ์ฒด์ ์ผ๋ก ๋ณ๋ ฌ ์คํ๋๋ค.
7.1.2 ์คํธ๋ฆผ ์ฑ๋ฅ ์ธก์
๋ณ๋ ฌํ๋ฅผ ์ด์ฉํ๋ฉด ์์ฐจ๋ ๋ฐ๋ณต์ ๋นํด ์ฑ๋ฅ์ด ์ข์์ง ๊ฒ์ด๋ผ ์ถ์ธกํ์ง๋ง
์ํํธ์จ์ด ๊ณตํ์์ ์ถ์ธก์ ์ํํ ๋ฐฉ๋ฒ์ด๋ค.
ํญ์ ์ธก์ ์ ํ๋ผ.
์๋ฐ ๋ง์ดํฌ๋ก๋ฒค์น๋งํฌ ํ๋์ค (JMH) ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ฐ๋จํ๊ณ ์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ ๋ฐฉ์์ ์ง์ํ๋ฉฐ ์์ ์ ์ผ๋ก ์๋ฐ ๊ฐ์ ๋จธ์ (JVM)์ ๋์์ผ๋ก ํ๋ ๋ฒค์น๋งํฌ๋ฅผ ๊ตฌํํ ์ ์๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(2, jvmArgs={"-Xms4G", "-Xmx4G"})
public class ParallelStreamBenchmark {
private static final long N = 10_000_000L;
@Benchmark
public long sequentialSum() {
return Stream.iterate(1L, i -> i + 1).limit(N)
.retduce(0L, Long::sum);
}
@TearDown(Level.Invocation)
public void tearDown() {
System.gc();
}
}
๋ฒค์น๋งํฌ๊ฐ ๊ฐ๋ฅํ ๊ฐ๋น์ง ์ปฌ๋ ํฐ์ ์ํฅ์ ๋ฐ์ง ์๋๋ก ํ์ ํฌ๊ธฐ๋ฅผ ์ถฉ๋ถํ๊ฒ ์ค์ ํ๊ณ
๋ฒค์น๋งํฌ๊ฐ ๋๋ ๋๋ง๋ค ๊ฐ๋น์ง ์ปฌ๋ ํฐ๊ฐ ์คํ๋๋๋ก ๊ฐ์ ํ๋ค.
์ด ์ฝ๋๋ฅผ ์คํํ ๋ JMH ๋ช ๋ น์ ํซ์คํ์ด ์ฝ๋๋ฅผ ์ต์ ํ ํ ์ ์๋๋ก 20๋ฒ์ ์คํํ๋ฉฐ
๋ฒค์น๋งํฌ๋ฅผ ์ค๋นํ ๋ค์ 20๋ฒ์ ๋ ์คํํด ์ต์ข ๊ฒฐ๊ณผ๋ฅผ ๊ณ์ฐํ๋ค.
์ฆ 20 + 20 ํ ๋ฐ๋ณต ์คํํ๋ค.
1
2
3
sequentialSum -> 121.843
iterativeSum -> 3.273
parallelSum -> 603.059
๋ณ๋ ฌ ๋ฒ์ ์ด ์ฟผ๋ ์ฝ์ด CPU๋ฅผ ํ์ฉํ์ง ๋ชปํ๊ณ ์์ฐจ ๋ฒ์ ์ ๋นํด 5๋ฐฐ๋ ๋๋ ธ๋ค.
- ๋ฐ๋ณต ๊ฒฐ๊ณผ๋ก ๋ฐ์ฑ๋ ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ง๊ธฐ ๋๋ฌธ์ ์ซ์๋ฅผ ๋ํ๋ ค๋ฉด ์ธ๋ฐ์ฑ์ด ํ์ํ๋ค.
- ๋ฐ๋ณต ์์ ์ ๋ณ๋ ฌ๋ก ์ํํ ์ ์๋ ๋ ๋ฆฝ ๋จ์๋ก ๋๋๊ธฐ๊ฐ ์ด๋ ต๋ค.
2๋ฒ์งธ์ ์ด์ ๋ก ์คํธ๋ฆผ์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ ์ ์๋๋ก ์ฒญํฌ๋ก ๋ถํ ํ ์ ์์๋ค.
์์ฐจ์ฒ๋ฆฌ ๋ฐฉ์๊ณผ ํฌ๊ฒ ๋ค๋ฅธ ์ ์ด ์์ด ์ค๋ ๋๋ฅผ ํ ๋นํ๋ ์ค๋ฒํค๋๋ง ์ฆ๊ฐํ๊ฒ ๋์๋ค.
๋ ํนํ๋ ๋ฉ์๋ ์ฌ์ฉ
LongStream.rangeClosed ๋ iterate ์ ๋นํด ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ด ์๋ค.
- ๊ธฐ๋ณธํ long ์ ์ง์ ์ฌ์ฉํ๋ฏ๋ก ๋ฐ์ฑ, ์ธ๋ฐ์ฑ ์ค๋ฒํค๋๊ฐ ์ฌ๋ผ์ง๋ค.
- ์ฝ๊ฒ ์ฒญํฌ๋ก ๋ถํ ํ ์ ์๋ ์ซ์ ๋ฒ์๋ฅผ ์์ฐํ๋ค.
1
2
3
4
5
6
7
@Benchmark
public long rangedSum() {
return LongStream.rangeClosed(1, N)
.reduce(0L, Long::sum);
}
rangedSum -> 5.315
1
2
3
4
5
6
7
8
@Benchmark
public long parallelRangedSum() {
return LongStream.rangeClosed(1, N)
.parallel()
.reduce(0L, Long::sum);
}
parallelRangedSum -> 2.677
๊ธฐ์กด์ iterate ํฉํ ๋ฆฌ ๋ฉ์๋๋ก ์์ฑํ ์์ฐจ ๋ฒ์ ์ ๋นํด ์คํธ๋ฆผ ์ฒ๋ฆฌ ์๋๊ฐ ๋นจ๋ผ์ก๊ณ
์์ฐจ ์คํ๋ณด๋ค ๋น ๋ฅธ ์ฑ๋ฅ์ ๊ฐ๋ ๋ณ๋ ฌ ๋ฆฌ๋์ฑ์ ๋ง๋ค์๋ค.
ํ์ง๋ง ๋ณ๋ ฌํ๊ฐ ์์ ๊ณต์ง๋ ์๋๋ผ๋ ์ฌ์ค์ ๊ธฐ์ตํด๋ผ.
์คํธ๋ฆผ์ ์ฌ๊ท์ ์ผ๋ก ๋ถํ ํด์ผ ํ๊ณ , ์๋ธ์คํธ๋ฆผ์ ์๋ก ๋ค๋ฅธ ์ค๋ ๋์ ๋ฆฌ๋์ฑ ์ฐ์ฐ์ผ๋ก ํ ๋นํ๊ณ , ์ด๊ฒ๋ค์ ํ๋์ ๊ฐ์ผ๋ก ํฉ์ณ์ผ ํ๋ค.
7.1.3 ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์ฌ๋ฐ๋ฅธ ์ฌ์ฉ๋ฒ
๋ณ๋ ฌ ์คํธ๋ฆผ์ ์๋ชป ์ฌ์ฉํ๋ฉด์ ๋ฐ์ํ๋ ๋ง์ ๋ฌธ์ ๋ ๊ณต์ ๋ ์ํ๋ฅผ ๋ฐ๊พธ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ์ผ์ด๋๋ค.
1
2
3
4
5
6
7
8
9
10
public long sideEffectSum(long n) {
Accumulator accumulator = new Accumulator();
LongStream.rangeClosed(1, n).forEach(accumulator::add);
return accumulator.total;
}
public class Accumulator {
public long total = 0;
public void add(long value) { total += value; }
}
์ด ์ฝ๋๋ ๋ณธ์ง์ ์ผ๋ก ์์ฐจ ์คํํ ์ ์๋๋ก ๊ตฌํ๋์ด ์์ผ๋ฏ๋ก ๋ณ๋ ฌ๋ก ์คํํ๋ฉด ์ฐธ์ฌ๊ฐ ์ผ์ด๋๋ค.
๋๊ธฐํ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค๋ณด๋ฉด ๊ฒฐ๊ตญ ๋ณ๋ ฌํ๋ผ๋ ํน์ฑ์ด ์์ด์ง๋ค.
7.1.4 ๋ณ๋ ฌ ์คํธ๋ฆผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ
- ํ์ ์ด ์์ง ์์ผ๋ฉด ์ง์ ์ธก์ ํ๋ผ.
๋ณ๋ ฌ ์คํธ๋ฆผ์ด ํญ์ ์์ฐจ ์คํธ๋ฆผ๋ณด๋ค ๋น ๋ฅธ ๊ฒ์ ์๋๋ค.
์ ์ ํ ๋ฒค์น๋งํฌ๋ก ์ง์ ์ฑ๋ฅ์ ์ธก์ ํ๋ ๊ฒ์ด ๋ฐ๋์งํ๋ค.
- ๋ฐ์ฑ์ ์ฃผ์ํ๋ผ.
์๋ ๋ฐ์ฑ๊ณผ ์ธ๋ฐ์ฑ์ ์ฑ๋ฅ์ ํฌ๊ฒ ์ ํ์ํฌ ์ ์๋ ์์์ด๋ค.
์๋ฐ 8์ ๋ฐ์ฑ ๋์์ ํผํ ์ ์๋๋ก ๊ธฐ๋ณธํ ํนํ ์คํธ๋ฆผ์ ์ ๊ณตํ๋ค.
- ๋ณ๋ ฌ ์คํธ๋ฆผ์์ ์ฑ๋ฅ์ด ๋จ์ด์ง๋ ์ฐ์ฐ์ด ์๋ค.
limit ์ด๋ findFirst ์ฒ๋ผ ์์์ ์์์ ์์กดํ๋ ์ฐ์ฐ์ ๋ณ๋ ฌ ์คํธ๋ฆผ์์ ์ํํ๋ฉด ๋น์ผ ๋น์ฉ์ ์น๋ฌ์ผ ํ๋ค.
๋์ findAny ๋ ์์์ ์์์ ์๊ด์์ด ์ฐ์ฐํ๋ฏ๋ก findFirst ๋ณด๋ค ์ฑ๋ฅ์ด ์ข๋ค.
์คํธ๋ฆผ์์ ์ํํ๋ ์ ์ฒด ํ์ดํ๋ผ์ธ ์ฐ์ฐ ๋น์ฉ์ ๊ณ ๋ คํ๋ผ.
์๋์ ๋ฐ์ดํฐ์์๋ ๋ณ๋ ฌํ ๊ณผ์ ์์ ์๊ธฐ๋ ๋ถ๊ฐ ๋น์ฉ์ ์์ํ ๋งํผ ์ด๋์ด ์๋ค.
์คํธ๋ฆผ์ ๊ตฌ์ฑํ๋ ์๋ฃ๊ตฌ์กฐ๊ฐ ์ ์ ํ์ง ํ์ธํ๋ผ.
ArrayList ๋ฅผ LinkedList ๋ณด๋ค ํจ์จ์ ์ผ๋ก ๋ถํ ํ ์ ์๋ค.
range ํฉํ ๋ฆฌ ๋ฉ์๋๋ก ๋ง๋ ๊ธฐ๋ณธํ ์คํธ๋ฆผ๋ ์ฝ๊ฒ ๋ถํ ํ ์ ์๋ค.
์คํธ๋ฆผ์ ํน์ฑ๊ณผ ํ์ดํ๋ผ์ธ ์ค๊ฐ ์ฐ์ฐ์ด ์คํธ๋ฆผ์ ํน์ฑ์ ์ด๋ป๊ฒ ๋ฐ๊พธ๋์ง์ ๋ฐ๋ผ ๋ถํด ๊ณผ์ ์ฑ๋ฅ์ด ๋ฌ๋ผ์ง ์ ์๋ค.
์ต์ข ์ฐ์ฐ์ ๋ณํฉ ๊ณผ์ ๋น์ฉ์ด ๋น์ธ๋ค๋ฉด ๋ณ๋ ฌ ์คํธ๋ฆผ์ผ๋ก ์ป์ ์ฑ๋ฅ ์ด์ต์ด ์๋ธ์คํธ๋ฆผ์ ๋ถ๋ถ ๊ฒฐ๊ณผ๋ฅผ ํฉ์น๋ ๊ณผ์ ์์ ์์๋ ์ ์๋ค.
7.2 ํฌํฌ/์กฐ์ธ ํ๋ ์์ํฌ
ํฌํฌ/์กฐ์ธ ํ๋ ์์ํฌ๋ ๋ณ๋ ฌํํ ์ ์๋ ์์ ์ ์ฌ๊ท์ ์ผ๋ก ์์ ์์ ์ผ๋ก ๋ถํ ํ ๋ค์
์๋ธํ ์คํฌ ๊ฐ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ํฉ์ณ ์ ์ฒด ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค๋๋ก ์ค๊ณ๋์๋ค.
7.2.1 RecursiveTask ํ์ฉ
์ค๋ ๋ ํ์ ์ด์ฉํ๊ธฐ ์ํด RecursiveTask<R> ์ ์๋ธํด๋์ค๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค.
RecursiveTask ๋ฅผ ์ ์ํ๊ธฐ ์ํด ์ถ์ ๋ฉ์๋ compute ๋ฅผ ๊ตฌํํด์ผ ํ๋ค.
1
protected abstract R compute();
compute ๋ ํ์คํธ๋ฅผ ์๋ธํ์คํฌ๋ก ๋ถํ ํ๋ ๋ก์ง๊ณผ
๋ ์ด์ ๋ถํ ํ ์ ์์ ๋ ๊ฐ๋ณ ์๋ธํ์คํธ์ ๊ฒฐ๊ณผ๋ฅผ ์์ฐํ ์๊ณ ๋ฆฌ์ฆ์ ์ ์ํ๋ค.
๋๋ถ๋ถ์ compute ๋ฉ์๋ ๊ตฌํ์ ๋ค์๊ณผ ๊ฐ์ ์์ฌ์ฝ๋๋ฅผ ์ ์งํ๋ค.
1
2
3
4
5
6
7
8
if (ํ์คํธ๊ฐ ์ถฉ๋ถํ ์๊ฑฐ๋ ๋ ์ด์ ๋ถํ ํ ์ ์์ผ๋ฉด) {
์์ฐจ์ ์ผ๋ก ํ์คํธ ๊ณ์ฐ
} else {
ํ์คํฌ๋ฅผ ๋ ์๋ธํ์คํฌ๋ก ๋ถํ
ํ์คํฌ๊ฐ ๋ค์ ์๋ธํ์คํฌ๋ก ๋ถํ ๋๋๋ก ์ด ๋ฉ์๋๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถํจ
๋ชจ๋ ์๋ธํ์คํฌ ์ฐ์ฐ์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆผ
๊ฐ ์๋ธํ์คํฌ์ ๊ฒฐ๊ณผ๋ฅผ ํฉ์นจ
}
์ด ์๊ณ ๋ฆฌ์ฆ์ ๋ถํ ์ ๋ณต ์๊ณ ๋ฆฌ์ฆ์ ๋ณ๋ ฌํ ๋ฒ์ ์ด๋ค.
7.2.2 ํฌํฌ/์กฐ์ธ ํ๋ ์์ํฌ๋ฅผ ์ ๋๋ก ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- join ๋ฉ์๋๋ฅผ ํ์คํฌ์ ํธ์ถํ๋ฉด ํ์คํฌ๊ฐ ์์ฐํ๋ ๊ฒฐ๊ณผ๊ฐ ์ค๋น๋ ๋๊น์ง ํธ์ถ์๋ฅผ ๋ธ๋ก์ํจ๋ค.
๋ฐ๋ผ์ ๋ ์๋ธํ์คํฌ๊ฐ ๋ชจ๋ ์์๋ ๋ค์์ join ์ ํธ์ถํด์ผ ํ๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด ๊ฐ๊ฐ์ ์๋ธํ์คํฌ๊ฐ ์๋ก ๋ค๋ฅธ ํ์คํฌ๊ฐ ๋๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ์ฑ๋ฅ์ด ํ๋ฝํ๋ค.
- RecursiveTask ๋ด์์๋
ForkJoinPool์invoke๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ๋ง์์ผ ํ๋ค.
๋์ compute ๋ fork ๋ฅผ ์ง์ ํธ์ถํ๋ผ.
์์ฐจ ์ฝ๋์์ ๋ณ๋ ฌ ๊ณ์ฐ์ ์์ํ ๋๋ง invoke ๋ฅผ ์ฌ์ฉํ๋ค.
- ์๋ธํ์คํฌ์
fork๋ฉ์๋๋ฅผ ํธ์ถํด์ForkJoinPool์ ์ผ์ ์ ์กฐ์ ํ ์ ์๋ค.
ํ์ชฝ ์์
์๋ fork ๋ณด๋ค compute ๋ฅผ ํธ์ถํ๋ ๊ฒ์ด ํจ์จ์ ์ด๋ค.
๋ ์๋ธํ์คํฌ์ ํ ํ์คํฌ์๋ ๊ฐ์ ์ค๋ ๋๋ฅผ ์ฌ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ถํ์ํ ํ์คํฌ๋ฅผ ํ ๋นํ๋ ์ค๋ฒํค๋๋ฅผ ํผํ ์ ์๋ค.
- ํฌํฌ/์กฐ์ธ ํ๋ ์์ํฌ๋ฅผ ์ด์ฉํ๋ ๋ณ๋ ฌ ๊ณ์ฐ์ ๋๋ฒ๊น ์ด ์ด๋ ต๋ค.
๋ณดํต stack trace ๋ก ๋ฌธ์ ๊ฐ ์ผ์ด๋ ๊ณผ์ ์ ์ฝ๊ฒ ํ์ธํ ์ ์์ง๋ง, ํ๋ ์์ํฌ์์๋ fork ๋ผ ๋ถ๋ฆฌ๋ ๋ค๋ฅธ ์ค๋ ๋์์ compute ๋ฅผ ํธ์ถํ๊ธฐ ๋๋ฌธ์ ๋์์ด ๋์ง ์๋๋ค.
- ๋ฉํฐ์ฝ์ด์ ๋ฌด์กฐ๊ฑด ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์์ฐจ ์ฒ๋ฆฌ๋ณด๋ค ๋น ๋ฅผ ๊ฑฐ๋ผ๋ ์๊ฐ์ ๋ฒ๋ ค๋ผ.
7.2.3 ์์ ํ์น๊ธฐ
์์
ํ์น๊ธฐ ๊ธฐ๋ฒ์์๋ ForkJoinPool ์ ๋ชจ๋ ์ค๋ ๋๋ฅผ ๊ฑฐ์ ๊ณต์ ํ๊ฒ ๋ถํ ํ๋ค.
๊ฐ๊ฐ์ ์ค๋ ๋๋ ํ ๋น๋ ํ์คํฌ๋ฅผ ํฌํจํ๋ ๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ๋ฅผ ์ฐธ์กฐํ๋ฉด์ ์์ ์ด ๋๋ ๋๋ง๋ค ํ์ ํค๋์์ ๋ค๋ฅธ ํ์คํฌ๋ฅผ ๊ฐ์ ธ์์ ์์ ํ๋ค.
ํ ์ค๋ ๋๋ ๋ค๋ฅธ ์ค๋ ๋๋ณด๋ค ์์ ์๊ฒ ํ ๋น๋ ํ์คํฌ๋ฅผ ๋ ๋นจ๋ฆฌ ์ฒ๋ฆฌํ ์ ์๋ค.
ํ ์ผ์ด ์์ด์ง ์ค๋ ๋๋ ์ ํด ์ํ๋ก ๋ฐ๋๋ ๊ฒ์ด ์๋๋ผ ๋ค๋ฅธ ์ค๋ ๋ ํ์ ๊ผฌ๋ฆฌ์์ ์์ ์ ํ์ณ์จ๋ค.
์์ ์์ ํ์ ์๋ ํ์คํฌ๋ฅผ ๋ ๊ฐ์ ์๋ธ ํ์คํฌ๋ก ๋ถํ ํ์ ๋,
๋ ์ค ํ๋์ ํ์คํฌ๋ฅผ ๋ค๋ฅธ ์ ํด ์์ ์๊ฐ ํ์ณ๊ฐ ์ ์๋ค.
์ฃผ์ด์ง ํ์คํฌ๋ฅผ ์์ฐจ ์คํํ ๋จ๊ณ๊ฐ ๋ ๋๊น์ง ์ด ๊ณผ์ ์ ์ฌ๊ท์ ์ผ๋ก ๋ฐ๋ณตํ๋ค.
7.3 Spliterator ์ธํฐํ์ด์ค
์๋ฐ 8์ Spliterator ๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค.
์ด๋ ๋ถํ ํ ์ ์๋ ๋ฐ๋ณต์๋ผ๋ ์๋ฏธ์ด๋ค.
1
2
3
4
5
6
public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super ?> action);
Spliterator<T> trySplit();
long estimateSize();
int characteristics();
}
- T๋
Spliterator์์ ํ์ํ๋ ์์์ ํ์์ ๊ฐ๋ฆฌํจ๋ค. tryAdvance๋ฉ์๋๋ ์์๋ฅผ ์๋นํ๋ฉฐ ํ์ํ ์์๊ฐ ๋จ์์์ผ๋ฉด true ๋ฅผ ๋ฐํํ๋ค.trySplit. ๋ฉ์๋๋ ์ผ๋ถ ์์๋ฅผ ๋ถํ ํด์ ๋ ๋ฒ์งธSpliterator๋ฅผ ์์ฑํ๋ค.Spliterator์์๋estimateSize๋ฉ์๋๋ก ํ์ํ ์์ ์ ์ ๋ณด๋ฅผ ์ ๊ณตํ ์ ์๋ค.
7.3.1 ๋ถํ ๊ณผ์
์คํธ๋ฆผ์ ์ฌ๋ฌ ์คํธ๋ฆผ์ผ๋ก ๋ถํ ํ๋ ๊ณผ์ ์ ์ฌ๊ท์ ์ผ๋ก ์ผ์ด๋๋ค.
trySplit ์ ๊ฒฐ๊ณผ๊ฐ null ์ด ๋ ๋๊น์ง ์ด ๊ณผ์ ์ ๋ฐ๋ณตํ๋ค.
Spliterator ํน์ฑ
Spliterator ๋ characteristics ๋ผ๋ ์ถ์ ๋ฉ์๋๋ ์ ์ํ๋ค.
์ด๋ ์์ฒด์ ํน์ฑ ์งํฉ์ ํฌํจํ๋ int ๋ฅผ ๋ฐํํ๋ค.
- ORDERED : ์ ํด์ง ์์๊ฐ ์์ด ์ ์ํด์ผ ํ๋ค.
- DISTINCT :
x.equals(y)๋ ํญ์ false ์ด๋ค. - SORTED : ๋ฏธ๋ฆฌ ์ ์๋ ์ ๋ ฌ ์์๋ฅผ ๋ฐ๋ฅธ๋ค.
- SIZED : ํฌ๊ธฐ๊ฐ ์๋ ค์ง ์์ค๋ก
Spliterator๋ฅผ ์์ฑํด์estimatedSize()๋ ์ ํํ ๊ฐ์ ๋ฐํํ๋ค. - NON-NULL : ํ์ํ ๋ชจ๋ ์์๋ null ์ด ์๋๋ค.
- IMMUTABLE : ๋ชจ๋ ์์ค๋ ๋ถ๋ณ์ด๋ค.
- CONCURRENT : ๋๊ธฐํ ์์ด ์ฌ๋ฌ ์ค๋ ๋์์ ์์ค๋ฅผ ๋์์ ๊ณ ์น ์ ์๋ค.
- SUBSIZED : ์์ ๋ฐ ๋ชจ๋ ํ์
Spliterator๋SIZED์ด๋ค.
7.3.2 ์ปค์คํ Spliterator ๊ตฌํํ๊ธฐ
๋ฌธ์์ด์ ๋จ์ด ์๋ฅผ ๊ณ์ฐํ๋ ๋จ์ํ ๋ฉ์๋๋ฅผ ๊ตฌํํด๋ณด์.
๋ค์์ ๋ฐ๋ณต ๋ฒ์ ์ด๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
public int countWordsIteratively(String s) {
int counter = 0;
boolean lastSpace = true;
for (char c : s.toCharArray()) {
if (Character.isWhitespace(c)) {
lastSpace = true;
} else {
if (lastSpace) counter++;
lastSpace = false;
}
}
}
ํจ์ํ์ผ๋ก ๋จ์ด ์๋ฅผ ์ธ๋ ๋ฉ์๋ ์ฌ๊ตฌํํ๊ธฐ
์ฐ์ String ์ ์คํธ๋ฆผ์ผ๋ก ๋ณํํด์ผ ํ๋ค.
1
2
Stream<Character> stream = IntStream.range(0, SENTENCE.length())
.mapToObj(SENTENCE::charAt);
์ง๊ธ๊น์ง ๋ฐ๊ฒฌํ ๋จ์ด ์๋ฅผ ๊ณ์ฐํ๋ int ๋ณ์์
๋ง์ง๋ง ๋ฌธ์๊ฐ ๊ณต๋ฐฑ์ด์๋์ง ์ฌ๋ถ๋ฅผ ๊ธฐ์ตํ๋ boolean ๋ณ์๊ฐ ํ์ํ๋ค.
์ด๋ค์ ์บก์ํํ๋ ์๋ก์ด ํด๋์ค WordCounter ๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class WordCounter {
private final int counter;
private final boolean lastSpace;
public WordCounter(int counter, boolean lastSpace) {
this.counter = counter;
this.lastSpace = lastSpace;
}
public WordCounter accumulate(Character c) {
if (Character.isWhitespace(c)) {
return lastSpace ? this : new WordCounter(counter, true);
} else {
return lastSpace ? new WordCounter(counter + 1, false) : this;
}
}
public WordCounter combine(WordCounter wordCounter) {
return new WordCounter(counter + wordCounter.counter, wordCounter.lastSpace);
}
public int getCounter() {
return counter;
}
}
์คํธ๋ฆผ์ ํ์ํ๋ฉด์ ์๋ก์ด ๋ฌธ์๋ฅผ ์ฐพ์ ๋๋ง๋ค accumulate ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
์๋ก์ด ๋น๊ณต๋ฐฑ ๋ฌธ์๋ฅผ ํ์ํ ํ ๋ง์ง๋ง ๋ฌธ์๊ฐ ๊ณต๋ฐฑ์ด๋ฉด counter ๋ฅผ ์ฆ๊ฐ์ํจ๋ค.
combine ์ ๋ฌธ์์ด ์๋ธ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ WordCounter ๊ฒฐ๊ณผ๋ฅผ ํฉ์น๋ค.
์ด์ ์คํธ๋ฆผ์ ๋ฆฌ๋์ฑ ์ฐ์ฐ์ ์ง๊ด์ ์ผ๋ก ๊ตฌํํ ์ ์๋ค.
1
2
3
4
5
6
7
8
private int countWords(Stream<Character> stream) {
WordCounter wordCounter = stream.reduce(new WordCounter(0, true),
WordCounter::accumulate,
WordCounter::combine);
return wordCounter.getCounter();
}
-> Found 19 words
WordCounter ๋ณ๋ ฌ๋ก ์ํํ๊ธฐ
1
2
3
countWords(stream.parallel())
-> Found 25 words
๋ณ๋ ฌ ์คํธ๋ฆผ์ ์ํ๋ ๊ฒฐ๊ณผ๊ฐ ๋์ค์ง ์๋๋ค.
์๋ ๋ฌธ์์ด์ ์์์ ์์น์์ ๋๋ก ๋๋๋ค๋ณด๋ ์์์น ๋ชปํ๊ฒ ํ๋์ ๋จ์ด๋ฅผ ๋๋ก ๊ณ์ฐํ๋ ์ํฉ์ด ๋ฐ์ํ ์ ์๋ค.
๋จ์ด๊ฐ ๋๋๋ ์์น์์๋ง ๋ถํ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค.
๊ทธ๋ฌ๋ ค๋ฉด ๋จ์ด ๋์์ ๋ฌธ์์ด์ ๋ถํ ํ๋ ๋ฌธ์ Spliterator ๊ฐ ํ์ํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class WordCounterSpliterator implements Spliterator<Character> {
private final String string;
private int currentChar = 0;
public WordCounterSpliterator(String string) {
this.string = string;
}
// ํ์ฌ ๋ฌธ์๋ฅผ ์๋นํ๊ณ ์๋นํ ๋ฌธ์๊ฐ ๋จ์์์ผ๋ฉด true ๋ฅผ ๋ฆฌํด
@Override
public boolean tryAdvance(Consumer<? super Character> action) {
action.accept(string.charAt(currentChar++));
return currentChar < string.length();
}
@Override
public Spliterator<Character> trySplit() {
int currentSize = string.length() - currentChar;
if (currentSize < 10) return null;
for (int splitPos = currentSize / 2 + currentChar; splitPost < string.length(); splitPos++) {
if (Character.isWhitespace(string.charAt(splitPos))) {
Spliterator<Character> spliterator =
new WordCounterSpliterator(string.substring(currentChar, splitPos));
currentChar = splitPost;
return spliterator;
}
}
return null;
}
@Override
public long estimateSize() {
return string.length() - currentChar;
}
@Override
public int characteristics() {
return ORDERED + SIZED + SUBSIZED + NON-NULL + IMMUTABLE;
}
}
tryAdvance๋ ํ์ฌ ์ธ๋ฑ์ค์ ๋ฌธ์๋ฅผConsumer์ ์ ๊ณตํ ํ ์ธ๋ฑ์ค๋ฅผ ์ฆ๊ฐํ๋ค.
์๋ก์ด ์ปค์ ์์น๊ฐ ์ ์ฒด ๋ฌธ์์ด ๊ธธ์ด๋ณด๋ค ์์ผ๋ฉด true ๋ฅผ ๋ฐํํ๋๋ฐ
์ด๋ ๋ฐ๋ณต ํ์ํ ๋ฌธ์๊ฐ ๋จ์์๋ค๋ ๋ป์ด๋ค.
trySplit์ ๋ฐ๋ณต๋ ์๋ฃ๊ตฌ์กฐ๋ฅผ ๋ถํ ํ๋ ๋ก์ง์ ํฌํจ, ๊ฐ์ฅ ์ค์ํ ๋ฉ์๋์ด๋ค.
๋ถํ ๋์์ ์ค๋จํ ํ๊ณ๋ฅผ ์ค์ ํด์ผ ํ๋ค.
์ค์ ์ดํ๋ฆฌ์ผ์ด์ ์์๋ ๋๋ฌด ๋ง์ ํ์คํฌ๋ฅผ ๋ง๋ค์ง ์๋๋ก ๋ ๋์ ํ๊ณ๊ฐ์ ์ค์ ํด์ผ ํ๋ค.
๋จ์ ๋ฌธ์ ์๊ฐ ํ๊ณ๊ฐ ์ดํ๋ฉด null ์ ๋ฐํํ์ฌ ๋ถํ ์ ์ค์งํ๋ค.
๋ถํ ์ด ํ์ํ ๊ฒฝ์ฐ ํ์ฑํ ๋ฌธ์์ด ์ฒญํฌ ์ค๊ฐ ์์น๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ถํ ํ๋๋ก ์ง์ํ๋ค.
ํ์ํด์ผ ํ ์์์ ๊ฐ์
estimatedSize๋ ํ์ฑํ ๋ฌธ์์ด ์ ์ฒด ๊ธธ์ด์ ๋ฐ๋ณต์ค์ธ ์์น์ ์ฐจ ์ด๋ค.characteristic๋ฉ์๋๋ ์ดSpliterator์ ํน์ฑ์ ํฌํจํ๋ค.
WordCounterSpliterator ํ์ฉ
์ด์ ์ด๋ฅผ ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์ฌ์ฉํ ์ ์๋ค.
1
2
3
4
Spliterator<Charater> spliterator = new WordCounterSpliterator(SENTENCE);
Stream<Character> stream = StreamSupport.stream(spliterator, true);
-> Found 19 words
์ด์ ๊ธฐ๋ํ๋ ์ถ๋ ฅ ๊ฒฐ๊ณผ๊ฐ ๋์๋ค.