Search
🏆

그로킹 동시성 [CH 2] - 순차 실행과 병렬 실행

AI custom autofill
Published
2025/03/30
Category
Programming
Tags
BookReview
간만에 다시 책 리뷰로….

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만으로는 동시성은 달성할 수 있어도 병렬성은 달성할 수 없다.
동시성과 병렬성의 차이
애플리케이션은 동시적이지만 병렬적이지 않을 수 있다.
일정한 시간 동안 두 가지 이상의 일(동시에 하지 않더라도 두 가지 일을 번갈아가며 할 수 있다.)을 처리한다.
애플리케이션은 병렬적이지만 동시적이지 않을 수 있다.
단일 작업의 하위 작업 여러 개를 동시에 처리 하는 경우
애플리케이션은 병렬적이지도 동시적이지도 않을 수 있다.
한 번에 한 가지 작업을 순차적으로 처리하며, 이 작업을 구성하는 하위 작업이 없을 때 해당
애플리케이션은 병렬적이면서 동시적일 수 있다.
여러 개의 작업을, 또는 단일 작업의 하위 작업 여러개를 동시에 (그리고 병렬로 실행해서) 처리할 때 해당한다.
동시성은 여러 가지 주제와 관계가 있다. 프로세스 간 상호작용, 자원(메모리 또는 파일, 입출력 접근)의 공유와 경쟁, 프로세스 간 동기화, 프로세스 간의 프로세서 시간 할당 등이 있다. 이들 문제는 멀티 프로세서나 분산 처리 환경에서만 발생하는 것이 아니며 단일 프로세서 시스템에서도 일어날 수 있는 문제다.
책을 읽어나가며, 개념적인 접근에 불과하겠지만 동시성과 병렬성을 고려해볼만한 큰 과제가 생각났다. 병렬처리 구간에서 동기화와 블로킹 때문에 난항을 겪었었던 순간에, 조금 더 리서치해보고 그림을 그려보고 병목구간에 대해 다 같이 고민해보았다면 어땠을까 라는 생각이 든다.