๊ธฐ์ฌ ๋ฒ์ญ
//Java 8์ ๋ณ๋ ฌ ๋ฐฐ์ด ์์
//Eric Bruno ์์ฑ, 2014๋
3์ 25์ผ //drdobbs.com/jvm/parallel-array-Operations-in-java-8/240166287 //Eric Bruno๋ ๊ธ์ต ๋ถ๋ฌธ ๋ฐ ๋ธ๋ก๊ทธ์์ ๊ทผ๋ฌด ์น์ฌ์ดํธ Dr. ๋์ค.
์๋ก์ด Java ๋ฆด๋ฆฌ์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐฐ์ด๊ณผ ๋ณ๋ ฌ๋ก ์ํธ ์์ฉํ๋ ๊ฒ์ด ๋ ์ฌ์์ ธ ์ต์ํ์ ์ฝ๋ฉ์ผ๋ก ์ฑ๋ฅ์ด ํฌ๊ฒ ํฅ์๋ฉ๋๋ค. ์ด์ ์ค๋ผํด์ ์ธ์ด ์ธก๋ฉด์์ ํฐ ๋ฐ์ ์ ์ด๋ฃฌ Java SE 8์ ์ถ์ํฉ๋๋ค. ์ด๋ฒ ๋ฆด๋ฆฌ์ค์ ์ค์ํ ๊ธฐ๋ฅ ์ค ํ๋๋ ํฅ์๋ ๋์์ฑ์ด๋ฉฐ, ๊ทธ ์ค ์ผ๋ถ๋ java.util.Arrays ๊ธฐ๋ณธ ํด๋์ค์ ๋ํ๋ฉ๋๋ค. ์ด ํด๋์ค์๋ ์๋ก์ด ๋ฉ์๋๊ฐ ์ถ๊ฐ๋์์ผ๋ฉฐ, ์ด ๊ธฐ์ฌ์์๋ ์ด์ ๋ํด ์ค๋ช
ํ๊ฒ ์ต๋๋ค. ์ด๋ค ์ค ์ผ๋ถ๋ JDK8์ ๋ ๋ค๋ฅธ ์๋ก์ด ๊ธฐ๋ฅ์ธ ๋๋ค์์ ์ฌ์ฉ๋ฉ๋๋ค. ํ์ง๋ง ์ฌ์
์ ์์ํฉ์๋ค.
๋ฐฐ์ด.paralellSort()
ParallelSort์ ๋ง์ ๊ธฐ๋ฅ์ ๋ฐฐ์ด์ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ๋ถํ ํ๊ณ ์ ๋ ฌํ ๋ค์ ๋์์ ์ต์ข
๋ฐฐ์ด๋ก ์ฌ๊ฒฐํฉํ๋ ๋ณ๋ ฌ ๋ณํฉ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค. ๊ธฐ์กด์ ์์ฐจ Arrays.sort ๋ฉ์๋ ๋์ ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ๋๊ท๋ชจ ๋ฐฐ์ด์ ์ ๋ ฌํ ๋ ์ฑ๋ฅ๊ณผ ํจ์จ์ฑ์ด ํฅ์๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์๋ ์ฝ๋๋ ๋์ผํ ๋ฐ์ดํฐ ๋ฐฐ์ด์ ์ ๋ ฌํ๊ธฐ ์ํด ์์ฐจ sort() ๋ฐ ๋ณ๋ ฌ parallelSort()๋ฅผ ์ฌ์ฉํฉ๋๋ค.
public class ParallelSort { public static void main(String[] args) { ParallelSort mySort = new ParallelSort(); int[] src = null; System.out.println("\nSerial sort:"); src = mySort.getData(); mySort.sortIt(src, false); System.out.println("\nParallel sort:"); src = mySort.getData(); mySort.sortIt(src, true); } public void sortIt(int[] src, boolean parallel) { try { System.out.println("--Array size: " + src.length); long start = System.currentTimeMillis(); if ( parallel == true ) { Arrays.parallelSort(src); } else { Arrays.sort(src); } long end = System.currentTimeMillis(); System.out.println( "--Elapsed sort time: " + (end-start)); } catch ( Exception e ) { e.printStackTrace(); } } private int[] getData() { try { File file = new File("src/parallelsort/myimage.png"); BufferedImage image = ImageIO.read(file); int w = image.getWidth(); int h = image.getHeight(); int[] src = image.getRGB(0, 0, w, h, null, 0, w); int[] data = new int[src.length * 20]; for ( int i = 0; i < 20; i++ ) { System.arraycopy( src, 0, data, i*src.length, src.length); } return data; } catch ( Exception e ) { e.printStackTrace(); } return null; } }
ํ
์คํธ๋ฅผ ์ํด ์ด๋ฏธ์ง์ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์ด์ ๋ก๋ํ๋๋ฐ, ์ด๋ 46,083,360๋ฐ์ดํธ๋ฅผ ์ฐจ์งํ์ต๋๋ค. (์ฌ์ฉ์์ ๋ฐ์ดํฐ๋ ์ด๋ฏธ์ง์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค.) ๋น์ ์ด ์ฌ์ฉํ ๊ฒ์
๋๋ค). 4์ฝ์ด ๋
ธํธ๋ถ์์ ๋ฐฐ์ด์ ์ ๋ ฌํ๋ ๋ฐ ์์ฐจ ์ ๋ ฌ ๋ฐฉ๋ฒ์ ๊ฑฐ์ 3,000๋ฐ๋ฆฌ์ด๊ฐ ๊ฑธ๋ ธ๊ณ , ๋ณ๋ ฌ ์ ๋ ฌ ๋ฐฉ๋ฒ์ ์ต๋ ์ฝ 700๋ฐ๋ฆฌ์ด๊ฐ ๊ฑธ๋ ธ์ต๋๋ค. ๋์ํ์ธ์. ์๋ก์ด ์ธ์ด ์
๋ฐ์ดํธ๋ก ์์
์ฑ๊ณผ๊ฐ 4๋ฐฐ ํฅ์๋๋ ๊ฒฝ์ฐ๋ ์์ฃผ ๋ฐ์ํ์ง ์์ต๋๋ค.
๋ฐฐ์ด.parallelPrefix()
parallelPrefix ๋ฉ์๋๋ ์ง์ ๋ ์ํ ํจ์๋ฅผ ๋ฐฐ์ด ์์์ ์งํฉ์ ์ผ๋ก ์ ์ฉํ์ฌ ๋ฐฐ์ด ๋ด์ ๊ฒฐ๊ณผ๋ฅผ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํฉ๋๋ค. ์ด๋ ๋๊ท๋ชจ ์ด๋ ์ด์ ์์ฐจ ์์
์ ๋นํด ์ต์ ๋ฉํฐ ์ฝ์ด ํ๋์จ์ด์์ ํจ์ฌ ๋ ํจ์จ์ ์
๋๋ค. ๋ค์ํ ๊ธฐ๋ณธ ์ ํ์ ๋ฐ์ดํฐ ์์
(์: IntBinaryOperator, DoubleBinaryOperator, LongBinaryOperator ๋ฑ)๊ณผ ๋ค์ํ ์ ํ์ ์ํ ์ฐ์ฐ์์ ๋ํด ์ด ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ด ๋ง์ด ์์ต๋๋ค. ๋ค์์ ์ด์ ์์ ๋์ผํ ๋ํ ์ด๋ ์ด๋ฅผ ์ฌ์ฉํ ๋ณ๋ ฌ ์ด๋ ์ด ์คํํน์ ์์
๋๋ค. ์ด ์์
์ 4์ฝ์ด ๋
ธํธ๋ถ์์ ์ฝ 100๋ฐ๋ฆฌ์ด ๋ง์ ์๋ฃ๋์์ต๋๋ค.
public class MyIntOperator implements IntBinaryOperator { @Override public int applyAsInt(int left, int right) { return left+right; } } public void accumulate() { int[] src = null; // accumulate test System.out.println("\nParallel prefix:"); src = getData(); IntBinaryOperator op = new ParallelSort.MyIntOperator(); long start = System.currentTimeMillis(); Arrays.parallelPrefix(src, new MyIntOperator()); long end = System.currentTimeMillis(); System.out.println("--Elapsed sort time: " + (end-start)); } ... }
๋ฐฐ์ด.parallelSetAll()
์๋ก์ด parallelSetAll() ๋ฉ์๋๋ ํจ์จ์ฑ์ ๋์ด๊ธฐ ์ํด ๋ณ๋ ฌ์ฑ์ ์ฌ์ฉํ์ฌ ๋ฐฐ์ด์ ์์ฑํ๊ณ ํด๋น ๊ฐ์ ์์ฑํ ํจ์์ ๋ฐ๋ผ ๊ฐ ๋ฐฐ์ด ์์๋ฅผ ๊ฐ์ผ๋ก ์ค์ ํฉ๋๋ค. ์ด ๋ฐฉ๋ฒ์ ๋๋ค(๋ค๋ฅธ ์ธ์ด์์๋ "ํด๋ก์ "๋ผ๊ณ ํจ)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค.
(๊ทธ๋ ์ต๋๋ค. ๋๋ค์ ํด๋ก์ ๋ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ด๊ฒ์ ์์ฑ์์ ์ค์์
๋๋ค.)
, ์ด๋ ํฅํ ๊ธฐ์ฌ์์ ๋
ผ์ํ JDK8์ ๋ ๋ค๋ฅธ ์๋ก์ด ๊ธฐ๋ฅ์
๋๋ค. -> ์ฐ์ฐ์๋ก ๊ตฌ๋ฌธ์ ์ฝ๊ฒ ์ธ์ํ ์ ์๋ ๋๋ค๋ ์ ๋ฌ๋ ๋ชจ๋ ์์์ ๋ํด ํ์ดํ ๋ค ์ค๋ฅธ์ชฝ์์ ์์
์ ์ํํ๋ค๋ ์ ๋ง ์์๋๋ฉด ์ถฉ๋ถํฉ๋๋ค. ์๋ ์ฝ๋ ์์ ์์๋ i๋ก ์ธ๋ฑ์ค๋ ๋ฐฐ์ด์ ๊ฐ ์์์ ๋ํด ์์
์ด ์ํ๋ฉ๋๋ค. Array.parallelSetAll()์ ๋ฐฐ์ด ์์๋ฅผ ์์ฑํฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ค์ ์ฝ๋๋ ์์์ ์ ์ ๊ฐ์ผ๋ก ํฐ ๋ฐฐ์ด์ ์ฑ์๋๋ค.
public void createLargeArray() { Integer[] array = new Integer[1024*1024*4]; // 4M Arrays.parallelSetAll( array, i -> new Integer( new Random().nextInt())); }
๋ณด๋ค ๋ณต์กํ ๋ฐฐ์ด ์์ ์์ฑ๊ธฐ(์: ์ค์ ์ผ์์ ํ๋
๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ ์์ฑํ๋ ์์ฑ๊ธฐ)๋ฅผ ์์ฑํ๋ ค๋ฉด ๋ค์๊ณผ ์ ์ฌํ ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค์์
public void createLargeArray() { Integer[] array = new Integer[1024*1024*4]; // 4M Arrays.parallelSetAll( array, i -> new Integer( customGenerator(getNextSensorValue()))); } public int customGenerator(int arg){ return arg + 1; // some fancy formula here... } public int getNextSensorValue() { // Just random for illustration return new Random().nextInt(); }
getNextSensorValue๋ถํฐ ์์ํ๊ฒ ์ต๋๋ค. ์ค์ ๋ก๋ ์ผ์(์: ์จ๋๊ณ)์ ํ์ฌ ๊ฐ์ ๋ฐํํ๋๋ก ์์ฒญํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์๋ฅผ ๋ค์ด ์์์ ๊ฐ์ด ์์ฑ๋ฉ๋๋ค. ๋ค์ customGenerator() ๋ฉ์๋๋ ์ ํํ ์ฌ๋ก์ ๋ฐ๋ผ ์ ํํ ๋
ผ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์์ ๋ฐฐ์ด์ ์์ฑํฉ๋๋ค. ์ฌ๊ธฐ์ ์ฝ๊ฐ์ ์ถ๊ฐ ์ฌํญ์ด ์์ง๋ง ์ค์ ๊ฒฝ์ฐ์๋ ๋ ๋ณต์กํด์ง๋๋ค.
๋ถํ ๊ธฐ๋ ๋ฌด์์
๋๊น?
๋์์ฑ๊ณผ ๋๋ค๋ฅผ ํ์ฉํ๋ Arrays ํด๋์ค์ ์ถ๊ฐ๋ ๋ ๋ค๋ฅธ ๊ธฐ๋ฅ์ ๋ฐฐ์ด์ ๋ฐ๋ณตํ๊ณ ๋ถํ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ Spliterator์
๋๋ค. ๊ทธ ํจ๊ณผ๋ ๋ฐฐ์ด์๋ง ๊ตญํ๋์ง ์๊ณ ์ปฌ๋ ์
ํด๋์ค ๋ฐ IO ์ฑ๋์๋ ์ ์๋ํฉ๋๋ค. ๋ถํ ๊ธฐ๋ ์๋์ผ๋ก ๋ฐฐ์ด์ ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก ๋ถํ ํ๋ ๋ฐฉ์์ผ๋ก ์๋ํ๋ฉฐ, ์ฐ๊ฒฐ๋ ํ์ ๋ฐฐ์ด์ ๋ํ ์์
์ ์ํํ๊ธฐ ์ํด ์๋ก์ด ๋ถํ ๊ธฐ๊ฐ ์ค์น๋ฉ๋๋ค. ๊ทธ ์ด๋ฆ์ ์ด๋ ๋ฐ๋ณต ์์
์ ์ฌ๋ฌ ๋ถ๋ถ์ผ๋ก "๋ถํ "ํ๋ Iterator๋ก ๊ตฌ์ฑ๋ฉ๋๋ค. ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ์ด๋ ์ด์์ ๋ถํ ๋ ์์
์ ์ํํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ์ ๋ํ ์์
์ ์ํํ๋ฉด ๋ณ๋ ฌ์ฑ์ ํ์ฉํฉ๋๋ค. ๊ฐ ํ์ ๋ฐฐ์ด์ ์ต์ ํฌ๊ธฐ์ ๊ฐ์ ๋ถํ ๋งค๊ฐ๋ณ์๋ฅผ ์ค์ ํ ์๋ ์์ต๋๋ค.
public void spliterate() { System.out.println("\nSpliterate:"); int[] src = getData(); Spliterator
spliterator = Arrays.spliterator(src); spliterator.forEachRemaining( n -> action(n) ); } public void action(int value) { System.out.println("value:"+value); // Perform some real work on this data here... }
์คํธ๋ฆผ - ์ฒ๋ฆฌ
๋ง์ง๋ง์ผ๋ก ๋ฐฐ์ด์์ ์คํธ๋ฆผ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์ด ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ฉด ์ ์ฒด ๋ฐ์ดํฐ ์ํ์ ๋ํ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ํ์ฉํ๊ณ ์คํธ๋ฆผ ์ํ์ค๋ก ์ผ๋ฐํํ ์ ์์ต๋๋ค. ๋ฐ์ดํฐ ์ปฌ๋ ์
๊ณผ ์๋ก์ด JDK8์ ์คํธ๋ฆผ ์ฌ์ด์ ์ฐจ์ด์ ์ ์คํธ๋ฆผ์ด ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ ์ปฌ๋ ์
์ ์ฌ์ฉํ๋ฉด ์์๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ์์
ํ ์ ์๋ค๋ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด ์ปฌ๋ ์
์ ์ฌ์ฉํ๋ฉด ์์๋ฅผ ์ถ๊ฐํ๊ณ ์ ๊ฑฐํ๊ณ ์ค๊ฐ์ ์ฝ์
ํ ์ ์์ต๋๋ค. ์คํธ๋ฆผ ์ํ์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ ์ธํธ์ ๊ฐ๋ณ ์์๋ฅผ ์กฐ์ํ ์ ์์ง๋ง ๋์ ๋ฐ์ดํฐ ์ ์ฒด์ ๋ํ ๊ธฐ๋ฅ์ ์ํํ ์ ์์ต๋๋ค. ์งํฉ์์ ํน์ ๊ฐ๋ง ์ถ์ถ(๋ฐ๋ณต ๋ฌด์), ๋ฐ์ดํฐ ๋ณํ ์์
, ๋ฐฐ์ด์ ์ต์๊ฐ๊ณผ ์ต๋๊ฐ ์ฐพ๊ธฐ, ๋งต ์ถ์ ํจ์(๋ถ์ฐ ์ปดํจํ
์ ์ฌ์ฉ๋จ) ๋ฐ ๊ธฐํ ์ํ ์ฐ์ฐ๊ณผ ๊ฐ์ ์ ์ฉํ ์์
์ ์ํํ ์ ์์ต๋๋ค. ๋ค์์ ๊ฐ๋จํ ์์์๋ ๋์์ฑ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ ๋ฐฐ์ด์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ๊ณ ์์๋ฅผ ํฉ์ฐํฉ๋๋ค.
public void streamProcessing() { int[] src = getData(); IntStream stream = Arrays.stream(src); int sum = stream.sum(); System.out.println("\nSum: " + sum); }
๊ฒฐ๋ก
Java 8์ ํ์คํ ์ธ์ด์ ๋ํ ๊ฐ์ฅ ์ ์ฉํ ์
๋ฐ์ดํธ ์ค ํ๋๊ฐ ๋ ๊ฒ์
๋๋ค. ์ฌ๊ธฐ์ ์ธ๊ธ๋ ๋ณ๋ ฌ ๊ธฐ๋ฅ, ๋๋ค ๋ฐ ๊ธฐํ ์ฌ๋ฌ ํ์ฅ ๊ธฐ๋ฅ์ ์ฐ๋ฆฌ ์ฌ์ดํธ์ ๋ค๋ฅธ Java 8 ๋ฆฌ๋ทฐ์ ์ฃผ์ ๊ฐ ๋ ๊ฒ์
๋๋ค.
GO TO FULL VERSION