2. 무어의 법칙[1]
1. 반도체 메모리칩의 성능 즉,
메모리의 용량이나 CPU의 속도가 18개월에서 24개월마다 2배씩 향상된다는 ‘기술 개발 속도에 관한 법칙'
2. 컴퓨팅 성능은 18개월마다 2배씩 향상
3. 컴퓨팅 가격은 18개월 마다 반으로 떨어짐
2004년 이후 깨짐
3. CPU 발전 방향[2]
1. 성능을 2배씩 향상 시키는데 한계를 부딪힘
2. CPU를 여러개를 묶어 하나의 칩으로 사용
3. 하나의 컴퓨터에 CPU 여러개를 장착
⇒ 소프트웨어에서 멀티코어 전략에 영향을 받
아 병행 처리나 병렬 처리 지원이 중요
4. 프로그램 언어 종류[3]
- 1945년 부터 2014년까지 프로그래밍 언어는 거의 매년 1개 이상 탄생
- 현재까지 공개된 프로그래밍 언어는 300개가 넘음
- JAVA는 가장 범용적으로 사용되는 언어
- GO 는 병행 처리에 중점을 둔 언어
5. JAVA[4]
- JVM(Java Virtual Machine)에서 구동
- 웹 개발에서 가장 많이 사용하는 언어
- 안드로이드용 소프트웨어 개발에 많이 사용
- 많은 종류의 무료 라이브러리 지원
- 현재 1.8 버젼까지 출시됨(2017)
6. Thread[5]
Program - 프로그램 언어를 통해 소스를 짜서 만든것
Process - 프로그램을 실행 시켜 동작 하는 상태
Thread
- 프로세스 내에서 실행 되는 흐름의 단위
Thread
- 프로세스 내에서 실행 되는 흐름의 단위
1.
프
로
그
램
은
하
나
이
상
의
Thread
를
가
짐
2.
프
로
그
램
환
경
에
따
라
둘
이
상
의
Thread
를
동
시
에
실
행
할
수
있
음
7. GO[6]
- 구글이 개발한 프로그램 언어
- 가비지 컬렉터를 가지고 있음
- 병행성(concurrent)를 잘 지원하는 컴파일 언어
- 현재 1.8 버젼까지 출시됨(2017)
8. Goroutines(이하 고루틴 으로 표기)[7]
- Go는 고루틴을 사용
- Java, C, C++ 과 같은 언어는 Thread를 사용
- 고루틴 vs JAVA 차이점
a. 메모리 소비
GO: 2kb <> Java : 1mb(500배 차이)
- Go의 경우 오직 2kb의 스택 공간만 필요
- Java의 경우 Thread의 메모리와 다른 Thread 메모리 간의 경비 역할을 하는 영역과 함께 1mb로 시작
9. Goroutines(이하 고루틴 으로 표기)[7]
- 고루틴 vs JAVA 차이점
b. 설치와 철거 비용
- Thread는 거대한 설치와 철거 비용을 가짐
- Thread >> 리소스 요청 >> OS >> 작업 종료 >> 리소스 반환
(해결 책으로 Thread Pool 생성 & 관리)
- 고루틴은 런타임에 만들어지고, 파괴 되는 작업들로 이루어짐 (매우 적은 비용이 사용 ⇒ Pool 필요 없음)
c. context switching 비용
- Thread가 blocking 될 경우 다른 스레드가 그 자리를 스케쥴링 함
이렇게 바뀌는 동안 모든 레지스터들을 저장 복구 해야 함 (16개의 범용 레지스터, PC, SP, segment 레지스터,
16개의 XMM레지스터, FP conprocessor state 16개의 AVX레지스터, 모든 MSR 등 을 저장/복구 해야함)
- 고루틴은 협조적으로 스케쥴링되고 교체가 일어날 때 3개의 레지스터만 저장/복구 함 (PC, SP, DX)
10. Java vs GO 병렬 처리 시뮬레이션
JAVA 와 GO를 이용하여 Thread-Ring이라는 프로그램을 작성 함
1. 이 프로그램은 503개의 Thread(GO의 경우 고루틴)을 가짐
2. 첫번째 Thread를 생성 하면서 내부 변수에 두번째 Thread의 수조값을 가짐
3. 두번째 Thread를 생성 하면서 내부 변수에 세번째 Thread의 주소 값을 가짐
4. 마지막 503번째 Thread는 내부 변수에 첫번째 Thread 주소값을 가짐
5. 이후 실행 시 횟수를 입력 받아 횟수 만큼 하나의 Thread만 동작 하고
나머지는 대기 하도록 처리
6. 입력 받은 횟수 만큼 동작이 끝났을 때 현재 스레드의 숫자를 출력 후 종료
언어 버젼
JAVA 1.8.0_121
GO 1.8.1
CPU Intel Core2 Quad Processor Q6600
OS Ubuntu
테
스
트
환
경
정
보
11. Java vs GO 병렬 처리 시뮬레이션 결과
횟수 500,000 5,000,000 50,000,000
SECOND
JAVA 3.42 32.81 304.63
GO 0.16 1.50 14.71
MEMORY
JAVA 36,116 36,148 37,032
GO ? 2,360 2,616
CPU
JAVA 3.71 36.20 340.15
GO 0.16 1.49 14.71
CPU LOAD(%)
JAVA 25 / 31 / 27 / 25 29 / 28 / 28 / 22 29 / 29 / 26 / 25
GO 0 / 0 / 0 / 94 1 / 100 / 3 / 1 1 / 1 / 70 / 30
12. 마치며...
- Go 언어를 설계할 때 특별히 중점을 둔 부분은 병행 처리임
- 병행 처리 방식은 통신 순차 프로세스(Communcationg Sequenrial Processes,
CSP) 방식에 근간을 둔 것으로 메모리를 공유 하는 것이 아니라 메시지를 전
달 하는 방식으로 동기화 함
- 각 프로그램 언어들은 특징이 있음
- 상황에 알맞은 프로그램 언어를 선택 하는 것이 중요
14. 출처
[1] 무어의 법칙 : http://plus.hankyung.com/apps/newsinside.view?aid=201510119448A
[2] CPU 발전 : http://www.bodnara.co.kr/bbs/article.html?num=112779
[3] 프로그램 언어 종류 : https://en.wikipedia.org/wiki/Timeline_of_programming_languages
[4] JAVA :
https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_(%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D_%EC%96%B8%EC%96
%B4)
https://zeroturnaround.com/rebellabs/a-short-history-of-nearly-everything-java/
[5] Thread : https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C
[6] GO : https://ko.wikipedia.org/wiki/Go_(%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D_%EC%96%B8%EC%96%B4)
[7] goroutines http://blog.nindalf.com/how-goroutines-work/
[8] benchmark : http://benchmarksgame.alioth.debian.org/u64q/go.html
Editor's Notes
지난 30여년간 CPU의 성능이 무어의 법칙대로 18개월마다 2배씩 빨라졌다.
하지만 어느 순간 한계에 부딪혔고, CPU를 제작하는 회사들은 CPU 여러개를 묶어 하나의 칩으로 사용하는 식으로 발전 방향을 우회 했다. 이제는 컴퓨터 하나에 CPU 여러 개를 장착해서 CPU 여러개가 동시에 계산을 수행하게 한다. 결과적으로는 더 빠른 계산이 가능해졌다. 필연적으로 소프트웨어에도 이런한 멀티 코어 전략에 영향을 받아 병행 처리나 병렬 처리를 지원하는 것이 필수 조건이 되었다.
지구상에 존재하는 프로그램 언어는 아주 많다. 위키백과에 따르면 1945년 부터 2014년 까지 프로그래밍 언어는 거의 매년 1개 이상 탄생했다. 중간에 사라진 언어도 있지만, 현재까지 공개된 프로그래밍 언어는 300 개가 넘는다.[1] 프로그램 언어들은 각기 특징을 가지고 있다. JAVA의 경우는 범용성을, Golang의 경우는 동시성을, C의 경우는 속도에 강점을 가지고 있다.
본 논문에서는 JAVA와 Golang을 이용하여 병렬 프로그램을 작성하고 성능을 비교 하여 언어가 가지는 특징에 대하여 이해하도록 한다.
1. JAVA [2]
2017년 5월 TIOBE programming community index[4] 에서 1위인 언어이다.
JAVA는 썬 마이크로시스템즈의 제임스 고슬링과 다른 연구원들이 개발한 객체지향적 프로그램 언어이며, 현재 오라클(2010년 썬마이크로시스템즈에서 합병됨)에서 무료로 제공 하고 있다.
현재는 웹 애플리케이션 개발에서 가장 많이 사용하는 언어 가운데 하나이고, 모바일 운영체제인 안드로이드용 소프트웨어 개발에도 널리 사용 된다.
자바를 다른 컴파일 언어와 구분 짓는 가장 큰 특징은 컴파일된 코드가 플랫폼 독립적이라는 점이다. 자바 컴파일러는 자바 언어로 작성된 프로그램을 바이트코드라는 특수한 바이너리 형태로 변환한다. 이 바이트 코드를 실행하기 위해서는 JVM(Java Virtual Machine)이라는 특수한 가상 머신이 필요한다. 이 가싱 머신은 자바 바이트코드를 어느 플랫폼에서나 동일한 형태로 실행시킨다. 때문에 자바로 개발된 프로그램은 CPU나 운영체제 의 종류에 관계 없이 JVM을 설치할 수 있는 시스템에서는 어디서나 실행할 수 있으며, 이 점은 웹 애플리케이션의 특성과 맞아 떨어져 폭발적인 인기를 끌게 되었다. 또한 OSMU(One Source Multi Use)로 범용적인 기업용 애플리케이션 개발에도 많이 사용 되고 있다.
2. Thread[6]
스레드에 대하여 이해하기 전에 먼저 프로세스(Process) 에 대하여 알아야 한다.
프로그램 언어를 통해 소스를 짜서 만든 것을 프로그램이라 하고, 이 프로그램을 실행 시켜 동작하게 만들면 프로세스라고 한다. 프로세스는 보통 하나 이상의 스레드를 가지고 있다.
스레드(thread)는 어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다. 일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티스레드(multithread)라고 한다.
3. Golang[7]
Go는 구글이 개발한 프로그램 언어로 가비지 컬렉터를 가지고 있으며, 병행성(concurrent)를 잘 지원하는 컴파일 언어다.
2009년 리눅스와 Mac OS X 플랫폼을 대상으로 공식 발표 되었다.
Go는 정적 타입 컴파일 언어의 효율성과 동적 언어처럼 쉬운 프로그래밍을 할수 있도록 하는 것을 목표로 한다.
Go 문법은 대체로 C 와 비슷하나, C 와 다르게 한 라인 끝의 세미콜론은 필수가 아닌 옵션이다. 병행성 프로그래밍을 다루기 위해 go와 select 키워드가 사용된다. 또한 그리 좋지 않은 하드웨어에서도 빠르게 컴파일될 수 있도록 디자인되었으며, 가비지 컬렉션이 되는 언어 이다.
Go를 이용해 프로그램들이 서로 소통하면서 상태를 공유하는 동시성(concurrency) 프로그램을 쉽게 만들 수 있다. 동시성이란, 멀티쓰레딩, 병렬컴퓨팅 뿐 아니라 비동기성 입출력 또한 포함 된다.
4. Goroutines
Go는 고루틴을 사용하고 자바, C++과 같은 언어는 스레드를 사용합니다. 둘간의 차이는 다음 3가지 요소를 통해서 확인 할 수 있다.
4.1 메모리 소비
고루틴은 생성하는데 많은 메모리를 필요로 하지 않습니다. 오직 2kb 의 스택공간만 필요로 합니다. 고루틴은 필요에 따라 힙저장 공간을 확보하여 사용 한다.
스레드는 스레드의 메모리와 다른 스레드의 메모리 간의 경비 역할을 하는 Guard page라고 불리는 메모리 영역과 함께 1mb(500배 차이) 로 시작 한다.
수신 요청을 처리하는 서버는 문제없이 요청 한 건당 하나의 고루틴을 만들 수 있지만, 요청 한 건당 하나의 스레드를 만들 경우 고루틴 보다 먼저 OutOfMemoryError가 발생 한다.
이런 문제는 자바에 한정되어 있는 것이 아니라, 동시성의 주요 수단으로 OS 스레드를 사용하는 언어라면 언젠가 이 문제가 발생 한다.
4.2 설치와 철거 비용
스레드는 거대한 설치와 철거 비용을 가진다. 왜냐면 스레드는 OS로 부터 리소스를 요청하고 작업이 끝나면 리소스를 돌려줘야 하기 때문이다. 이 문제의 차선책으로 스레드의 Pool을 생성하고 관리하는 것이다. 대조적으로 고루틴은 런타임에서 만들어지고 파괴되는 작업들로 이루어져 매우 적은 비용이 사용된다. 때문에 고루틴의 매뉴얼 관리는 지원 하지 않는다.
4.3. context switching 비용
스레드가 Blocking된다면 다른 스레드가 그 자리를 스케쥴링 해야 한다. 스레드들은 우선적으로 스케쥴링되고 스레드가 바뀔동안 스케쥴러는 모든 레지스터들을 저장/복구 해야 한다. 즉 16개의 범용 레지스터, PC(Program Counter), SP(Stack Pointer), segment 레지스터, 16개의 XMM 레지스터, FP coprocessor state, 16개의 AVX레지스터, 모든 MSR등을 저장/복구 해야 한다. 이것은 스레드들간의 전환이 있을때 매우 중요 하다.
고루틴은 협조적으로 스케쥴링되고 교체가 일어날 때 오직 3개의 레지스터만 저장/복구 된다. 바로 Program Counter, Stack Pointer, 그리고 DX 이다. 따라서 스레드에 비해 아주 적은 비용이 든다.
다른 언어와 마찬가지로 하나의 고루틴보다 더 많은 고루틴들에 의해 공유된 리소스의 동시적인 접근을 방지하는 것이 중요하다. 고루틴간의 데이터 전송은 Channel을 사용하는 것이 좋다.
4. Goroutines
Go는 고루틴을 사용하고 자바, C++과 같은 언어는 스레드를 사용합니다. 둘간의 차이는 다음 3가지 요소를 통해서 확인 할 수 있다.
4.1 메모리 소비
고루틴은 생성하는데 많은 메모리를 필요로 하지 않습니다. 오직 2kb 의 스택공간만 필요로 합니다. 고루틴은 필요에 따라 힙저장 공간을 확보하여 사용 한다.
스레드는 스레드의 메모리와 다른 스레드의 메모리 간의 경비 역할을 하는 Guard page라고 불리는 메모리 영역과 함께 1mb(500배 차이) 로 시작 한다.
수신 요청을 처리하는 서버는 문제없이 요청 한 건당 하나의 고루틴을 만들 수 있지만, 요청 한 건당 하나의 스레드를 만들 경우 고루틴 보다 먼저 OutOfMemoryError가 발생 한다.
이런 문제는 자바에 한정되어 있는 것이 아니라, 동시성의 주요 수단으로 OS 스레드를 사용하는 언어라면 언젠가 이 문제가 발생 한다.
4.2 설치와 철거 비용
스레드는 거대한 설치와 철거 비용을 가진다. 왜냐면 스레드는 OS로 부터 리소스를 요청하고 작업이 끝나면 리소스를 돌려줘야 하기 때문이다. 이 문제의 차선책으로 스레드의 Pool을 생성하고 관리하는 것이다. 대조적으로 고루틴은 런타임에서 만들어지고 파괴되는 작업들로 이루어져 매우 적은 비용이 사용된다. 때문에 고루틴의 매뉴얼 관리는 지원 하지 않는다.
4.3. context switching 비용
스레드가 Blocking된다면 다른 스레드가 그 자리를 스케쥴링 해야 한다. 스레드들은 우선적으로 스케쥴링되고 스레드가 바뀔동안 스케쥴러는 모든 레지스터들을 저장/복구 해야 한다. 즉 16개의 범용 레지스터, PC(Program Counter), SP(Stack Pointer), segment 레지스터, 16개의 XMM 레지스터, FP coprocessor state, 16개의 AVX레지스터, 모든 MSR등을 저장/복구 해야 한다. 이것은 스레드들간의 전환이 있을때 매우 중요 하다.
고루틴은 협조적으로 스케쥴링되고 교체가 일어날 때 오직 3개의 레지스터만 저장/복구 된다. 바로 Program Counter, Stack Pointer, 그리고 DX 이다. 따라서 스레드에 비해 아주 적은 비용이 든다.
다른 언어와 마찬가지로 하나의 고루틴보다 더 많은 고루틴들에 의해 공유된 리소스의 동시적인 접근을 방지하는 것이 중요하다. 고루틴간의 데이터 전송은 Channel을 사용하는 것이 좋다.