간만에 다시 책 리뷰로….
2.1 돌아보기: 프로그램이란 무엇인가?
일반적으로 프로그램은 컴퓨터가 수행하거나 실행하는 일련의 명령이다.
프로그램을 실행하는 것은 레시피를 따라 조리하는 것에 비유할 수 있다.
우리 손에는 레시피(프로그램)가 있고, 요리사(프로세서, CPU)가 있으며, 재료(프로그램에 입력되는 데이터)도 있다.
•
프로세서는 스스로 일을 할 수 없다. 프로세서가 갖는 모든 ‘지적인’ 힘은 실행하는 프로그램이 무엇이냐에 따라 결정된다.
•
개발자는 프로세서에게 수행시키려는 작업을 프로그래밍 언어로 기술
•
소스 코드를 CPU가 이해할 수 있게 컴파일러라는 프로그램을 통해 기계어로 번역하여 실행파일로 변환한다.
•
CPU가 여러 명령을 다루는 가장 기본적인 방식은 순차 실행(Serial Execution)이다.
2.2 순차실행
우리는 프로그래밍할 때 주어진 문제를 잘게 쪼개 간단한 작업으로 나누고, 이들을 하나씩 연속적으로(serially) 실행한다.
만약 흰 빨래, 색깔 있는 빨래, 침대 시트를 세탁하려고 할 때, 세탁을 마치는 데 필요한 최소 시간은 세탁기 속도와 빨래 양에 의해 결정된다.
하나의 실행 단위가 끝날 때까지는 처리 자원을 이용할 수 없다.
2.3 순차 컴퓨팅
동적이고 시간과 관련된 현상을 나타낼 때는 순차적(sequential)이라는 용어를 쓴다.
이전 단계가 완료되지 않아도 수행할 수 있는 단계가 있는지 살펴보면, 순차 실행이 꼭 필요한 작업을 걸러낼 수 있다.
순차 프로그래밍의 반대 개념이 동시 프로그래밍이다. 동시성은 임의의 순서로 실행해도 같은 결과를 낳는 독립적인 연산이 있다는 것을 전제로 삼는 개념이다.
2.3.1 순차 컴퓨팅의 장점과 단점
•
단순성(장점)
◦
명확하며 예측가능
◦
작업을 분할할 때도 자연스럽게 작업의 순서를 생각하게 된다.
▪
먼저 식사를 하고, 설거지를 한 다음, 요리를 한다는 것은 이치에 맞지 않는다.
◦
직관적이다.
◦
어떤 단계를 실행할 때 이전 단계가 실행됐는지 일일이 확인할 필요가 없다.
▪
이전 작업의 실행이 끝나지 않았다면 현재 작업은 실행되지도 않았을 것이기 때문이다.
•
확장성(단점)
◦
시스템이 더욱 많은 일을 처리할 수 있게 하는 능력 또는 그러한 잠재력이다.
◦
처리 자원을 시스템에 추가하여 성능을 증가시킬 수 있는 시스템을 확장성이 뛰어나다고 표현
▪
자원(CPU, 메모리 등)의 성능을 높이는 것 뿐 → 수직 확장 (CPU의 최고 성능으로 확장 폭이 제한)
•
오버헤드(단점)
◦
프로그램을 실행할 때 프로그램의 각 단계가 서로 통신하거나 동기화 할 필요가 없다.
◦
프로그램이 잘 돌아간다고 해도 가용 자원을 모두 사용하지 않아 효율성이 떨어지거나 불필요한 비용이 발생할 수 있다.
▪
심지어 싱글 코어 시스템조차도 모두 활용하지 못할 수 있다.
2.4 병렬실행
토마토를 키우는 데 어림잡아 4개월이 걸린다고 한다. 그렇다면 1년에 키울 수 있는 토마토의 수는 3개다. 라는 말은 사실일까? 거짓일까?
당연히 거짓이며, 토마토를 한 번에 두 포기 이상 키울 수 있기 때문이다.
•
한 번에 한 가지 일만 할 수 있다는 가정을 내려놓으면, 일을 병렬(parallel)로 할 수 있는 가능성이 생긴다.
2.4.1 세탁 속도를 빠르게 하는 방법
만약 우리에게 2시간이 주어졌고 한 시간에 세탁기 한 번을 돌릴 수 있는데, 4바구니의 빨래감이 있다면?
만약 세탁기가 2대 이상이라면 문제가 없다. 그렇기에 우리는 코인 세탁소로 가서 어렵지 않게 네 번 분량의 빨랫감을 세탁기 네 대에 나눠 넣고 동시에 돌릴 수 있다. 이제 세탁기 네 대가 병렬로 돌아가고 있다. 처리율이 네 배로 증가한 셈이다.
바로 이 경우가 수평 확장에 해당한다.
병렬 실행(parallel execution)이란 작업을 물리적으로 동시에 실행하는 것을 말하며, 순차 실행의 반대 개념이다.
2.5 병렬 컴퓨팅을 위해 필요한 것
2.5.1 작업 독립성
병렬 컴퓨팅에서는 동시에 서로 독립적으로 실행할 수 있는 작업으로 문제를 분할해서 지연 시간을 줄이는 전략을 쓴다.
•
규모가 큰 프로그램은 보통 여러 개의 더 작은 프로그램으로 구성된다.
•
여러 처리 자원이 작업을 임의의 순서로 처리해도 결과가 동일해야 한다.
•
어떤 프로그램을 병렬 실행할 수 있는지 알아보려면 어떤 작업으로 분해되었고, 각 작업이 독립적으로 실행 가능한지를 살펴보아야 한다. (작업의 분해(decomposition))
•
병렬 실행할 수 있는 프로그램은 모두 순차 실행이 가능하지만, 그 반대는 성립하지 않는다.
일부 작업은 독립적이지만, 이전 작업의 실행이 필요한 작업도 섞여 있다. 이런 경우에는 개발자가 서로 의존적인 작업의 순서를 맞춰 동기화(synchronize)해야 정확한 처리 결과를 얻을 수 있다. (다른 작업에 의존하는 작업의 실행을 잠시 블록하고(blocking) 자신이 의존하는 작업이 끝날 때까지 대기시킨다.)
•
간단한 순차적 프로그램에 비해 병렬 프로그램은 작성하는 데도 만만치 않은 어려움을 겪는다.
◦
하지만 도전할 만한 가치가 있다. 병렬 프로그램을 제대로 작성했다면 프로그램의 처리율이 증가해 더 큰 문제를 빨리 해결하거나, 같은 시간 안에 작업을 더 많이 처리할 수 있게 된다.
동기화가 필요하지 않거나 적게 필요한 작업을 처치 곤란 병렬(emabarrasingly parallel)이라고 한다.
•
프로세스 간의 통신이 비교적 많지 않다는 특징 → 높은 성능을 보이는 핵심
2.5.2 하드웨어 지원
여러 개의 처리 자원을 갖춘 하드웨어가 있어야 한다. 두 개 이상의 처리 자원을 갖추고 있지 못하면 실질적인 병렬성을 달성할 수 없다.
2.6 병렬 컴퓨팅
벙렬 컴퓨팅은 크고 복잡한 문제를 여러 개의 작은 작업으로 분해하고, 이 작업들을 런타임 시스템 계층에서 병렬로 실행해 문제를 효율적으로 해결하는 방식을 말한다.
•
처리 자원이 많고 분해한 작업의 수가 적을수록 처리 속도가 빨라진다.
•
사용자가 저수준 병렬화를 신경쓰지 않아도 병렬 프로그래밍을 편리하게 구현할 수 있다.
◦
MATLAB에는 parfor라는 문법으로 간단하게 for 반복문을 병렬로 실행할 수 있다.
◦
파이썬도 joblib 패키지의 Parallel 클래스를 사용하면 아주 간단하게 병렬성을 달성가능.
2.7 암달의 법칙
언뜻 생각하면 프로세서의 수를 무한정 늘리면 시스템도 그에 맞춰 빨라질 수 있을 것 같다. 하지만 그렇지 않다!
병렬 알고리즘에도 순차적인 부분이 일부있지만, 대체로 순수 병렬적인 부분과 순수 순차적인 부분으로 나누어볼 수 있다.
•
결국 가장 느린 순차적인 부분의 속도가 병렬 프로그램의 속도가 된다.
•
프로그램의 순차적인 부분은 속도를 높일 수 없기 때문에 처리 자원을 늘려도 소용이 없다.
◦
병렬 컴퓨팅을 적용할 수 있는 최고 속도가 프로그램의 순차적 부분에 의해 제약을 받는다.
◦
추가되는 프로세서 처음 몇 개까지는 성능이 눈에 띄게 향상되지만, 점점 숫자를 늘릴수록 성능 향상의 폭은 줄어든다.
▪
프로세서 2,500개로 100배의 성능 향상을 얻으려면 프로그램에서 순차적인 부분이 1% 이하여야 한다.
암달의 법칙은 프로그램을 병렬화하는 이익이 어느 정도인가를 간단히 가늠해 볼 수 있는 편리한 도구이다.
2.8 구스타프슨의 법칙
프로그램 전체는 불가능하더라도, 성능이 가장 중요한 부분에서는 병렬성을 이용해 프로그램의 속도를 향상시킬 수 있다. (그래도 일반적인 문제에서는 명확한 한계가 존재한다.)
암달의 법칙은 문제의 크기는 고정한 채 병렬 프로그램의 실행 시간이 얼마나 줄어드는지만 다룬다. 그러나 실행 시간을 상수로 고정하고 문제의 크기를 증가시켜도 실행 속도(처리율)의 증가를 관찰할 수 있다. 구스타프슨의 법칙(Gustafson’s Law)은 이러한 관찰을 통해 나왔다.
작업의 양을 계속 늘릴 수 있다면 프로그램의 순차적인 부분의 영향은 점점 줄어들고 프로세서의 수를 늘릴 때마다 일정 수준의 속도 증가 효과를 볼 수 있다.
2.9 동시성 vs 병렬성
일반적으로 동시(concurrent)와 병렬(parallel)은 대부분 서로 동의어로 쓰인다.
동시 프로그래밍과 병렬 프로그래밍은 잘 구별해서 써야 한다. 이 두 가지는 서로 다른 개념적 수준에서 다른 목표를 추구하기 떄문이다.
동시성
•
여러 작업을 시작, 실행, 완료하는 과정이 서로 중첩된 시간에서 특별히 정해진 순서 없이 일어나는 것
◦
샐러드 재료를 다듬으며 가스레인지 위에 있는 수프를 저어야 하는 요리사
▪
동시적이지만, 병렬적이지는 않다.
•
처리 자원의 동시성은 전적으로 처리 자원의 이동에 달려 있다.
병렬성
•
여러 작업을 컴퓨팅 자원(멀티 프로세서)을 이용해 병렬로 동시에 실행하는 것
•
구현의 속성(implementation property)이다.
•
작업을 물리적으로 동시 실행하는 것이므로 처리 자원을 여러 개 갖춘 하드웨어가 필요하다. 따라서 하드웨어 계층의 개념이다.
◦
샐러드 재료를 다듬는 요리사 + 수프를 젓는 요리사
▪
동시적이자 병렬적
동시 계산은 결과의 정확도를 해치지 않는 선에서 병렬화할 수 있지만, 동시성 그 자체는 병렬성을 담보하지 않는다. 병렬성 역시 그 자체로는 동시성을 담보하지 않는다.
프로그램의 동시성은 작성된 프로그래밍 언어와 코드에 크게 좌우되지만, 병렬성은 프로그램의 실제 실행 환경에 더 큰 영향을 받는다.
•
싱글 코어 CPU만으로는 동시성은 달성할 수 있어도 병렬성은 달성할 수 없다.
동시성과 병렬성의 차이
•
애플리케이션은 동시적이지만 병렬적이지 않을 수 있다.
◦
일정한 시간 동안 두 가지 이상의 일(동시에 하지 않더라도 두 가지 일을 번갈아가며 할 수 있다.)을 처리한다.
•
애플리케이션은 병렬적이지만 동시적이지 않을 수 있다.
◦
단일 작업의 하위 작업 여러 개를 동시에 처리 하는 경우
•
애플리케이션은 병렬적이지도 동시적이지도 않을 수 있다.
◦
한 번에 한 가지 작업을 순차적으로 처리하며, 이 작업을 구성하는 하위 작업이 없을 때 해당
•
애플리케이션은 병렬적이면서 동시적일 수 있다.
◦
여러 개의 작업을, 또는 단일 작업의 하위 작업 여러개를 동시에 (그리고 병렬로 실행해서) 처리할 때 해당한다.
동시성은 여러 가지 주제와 관계가 있다. 프로세스 간 상호작용, 자원(메모리 또는 파일, 입출력 접근)의 공유와 경쟁, 프로세스 간 동기화, 프로세스 간의 프로세서 시간 할당 등이 있다. 이들 문제는 멀티 프로세서나 분산 처리 환경에서만 발생하는 것이 아니며 단일 프로세서 시스템에서도 일어날 수 있는 문제다.
책을 읽어나가며, 개념적인 접근에 불과하겠지만
동시성과 병렬성을 고려해볼만한 큰 과제가 생각났다.
병렬처리 구간에서 동기화와 블로킹 때문에 난항을 겪었었던 순간에,
조금 더 리서치해보고 그림을 그려보고 병목구간에 대해 다 같이 고민해보았다면 어땠을까 라는 생각이 든다.