백엔드 개발자들이 알아야할 동시성 1 — Concurrency와 Parallelism

Choi Geonu
5 min readJan 26, 2022

백엔드 개발자들이 알아야할 동시성에 대해 이야기하려고 합니다. 비동기 네트워킹, 코루틴, 이벤트 드리븐 시스템 등등 네트워킹을 위한 많은 용어들이 존재하는데, 이에 대한 여러분들의 모든 궁금증을 풀어드리려 동시성 시리즈를 연재하려 합니다.

중요한 이야기를 시작하기에 앞서, 알아야할 몇가지 개념에 대해서 먼저 설명하려고 합니다.

Concurrency와 Parallelism

Concurrency와 Parallelism은 해묵은 주제입니다. 하지만 이 차이에 대해서 이해하고 시작하는것이 너무나 중요하기에 먼저 짚고 넘어가려합니다.

Parallelism (병렬성)

Parallelism은 어떠한 작업이 하위작업으로 나뉘어 물리적으로 동시에 처리가 되는 일을 의미합니다.

예를 들면, 행렬 곱셈이 대표적인 Parallelism의 분야라고 할 수 있습니다.

위와 같은 행렬 연산이 있을 때, 연산 결과의 각 요소를 순차적으로 계산한다면 많은 연산 시간이 소요될 것입니다.

사이즈가 NxM인 행렬과 MxL인 행렬을 곱하면 O(NxMxL) 의 시간이 소요되겠죠. 하지만 충분한 양의 연산 장치가 있다면, 각 요소의 값들을 동시에 계산해 O(M)의 시간 밖에 소요되지 않을 수 있을것입니다.

이를 일반화 할 수 있는 대표적인 사례는 Monoid입니다. Monoid는 다음 세가지 성질을 만족하는 함수 및 데이터 타입입니다.

1. 결합법칙이 성립한다.

Monoid 함수 f 가 있을 때, 임의의 값 a, b, c 에 대해서 다음과 같은 교환법칙이 성립해야 합니다.

f(a, f(b, c)) = f(f(a, b), c)

2. 항등원이 존재한다.

임의의 Monoid 함수 f, 값 x 에 대해서 다음과 같은 고정 값 i 가 존재해야 합니다.

f(i, x) = f(x, i) = x

3. 닫혀있어야 한다.

임의의 값 a, b에 대해서 f(a, b) 의 결과인 c 는 항상 f 의 인자로 사용될 수 있어야합니다.
이러한 규칙들이 복잡해 보이지만 사실 에시를 들면 매우 간단한 사례라는것을 알 수 있습니다. 대표적인 Monoid의 예시는 덧셈과 곱셈입니다.

덧셈을 예로 들면, 임의의 수 a, b, c 에 대해서 항상 a + (b + c) = (a + b) + c 를 만족하고 a + 0 = 0 + a = a를 만족합니다.
마찬가지로 곱셉의 경우에도 임의의 수 a, b, c 에 대해서 항상 a x (b x c) = (a x b) x c 를 만족하고 a x 1 = 1 x a = a 를 만족하지요.

이러한 Monoid는 매우 쉽게 Parallelism을 이용한 최적화를 이룰 수 있는데, 다음과 같은 변환을 통해서 입니다.

f(1, f(2, f(3, ... f(9999, 10000)... )))

이렇게 N개의 중첩된 연산을 순차적으로 계산한다면 O(N)의 연산시간이 소요될 것입니다.

하지만 위와 같은 계산은 다음과 같이 변환할 수 있지요.

f(f(f(1, 2), f(3, 4)), f(5, 6), ... f(9999, 10000)...))

f 가 덧셈이라면 다음과 같은 계산으로 나타낼 수 있겠지요.

(1 + 2) + (3 + 4) + ... + (9997 + 9998) + (9999 + 10000)
= (3 + 7) + ... + (19995 + 19999)
...
= 12502500 + 37502500
= 50005000

이렇게 한다면 N개 이상의 연산장치가 존재할 경우 연산에 필요한 시간은 O(log2(N))이 됩니다.

실제로 1부터 8까지 더하는 연산은 다음과 같이 계산될 수 있습니다.

각 단계는 충분한 수의 연산장치가 있다면 모두 한번에 계산이 가능한 연산입니다. 이렇게 3번의 단계만 거치면 위 덧셈 연산은 끝이 나고, 이 연산의 횟수는 log2(8) = 3 과 일치하지요.

이렇게 볼 수 있듯이, Monoid는 Parallelism을 통해 효율적으로 계산할 수 있는 대표적인 연산이 됩니다.

Concurrency (병행성)

Parallelism이 하나의 문제를 풀기 위해 여러 작업을 동시에 수행하는것이라 한다면, Concurrency는 여러 작업을 동시에 수행하는것 그 자체, 또는 동시에 수행되는것 처럼 보이는것을 의미합니다.

웹서버를 예로 들면 다음과 같이 여러 요청을 동시에 처리하는것을 예로 들 수 있습니다.

위 상황에서 CPU는 2대이지만, CPU들은 요청을 한번에 하나씩 처리하지 않고 여러개의 요청을 Time-sharing 방식으로 처리하게 됩니다. 이처럼 실제로 동시에 수행되는것과 관계 없이, 각 작업 전체를 순차적으로 처리하는 것이 아닌 여러 방법에 따라 동시에 수행하는것을 Concurrency라고 이야기합니다.

우리가 알아야할 것

이 연재 시리즈의 주제는 백엔드 개발자가 알아야할 내용이기에 주로 다룰 내용은 Parallelism보단 Concurrency가 될 것 입니다. 둘의 차이를 명확하게 앎으로써 주제에 더 정확히 집줄할 수 있게 되기를 바라는 마음으로 첫번째 포스팅을 마무리합니다 😊

--

--