๐ฆ 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
์ด์ ๊ธฐ๋ํ๋ ์ถ๋ ฅ ๊ฒฐ๊ณผ๊ฐ ๋์๋ค.