병렬프로그래밍 - 동시성 Concurrency 과 병렬성 Parallelism
무슨 차이?
- 사진 부터 보자
Concurrent = two queues and one coffee machine.
Parallel = Two queues and two coffee machines.
동시성과 병렬성을 설명하는 한장의 그림이다.
Concurrency = 동시성, 동시 실행
Parallelism = 병렬성, 평행성, 병렬 실행, 평행 실행
먼저 Process와 Thread 부터
Process?
- Process는 Program이 실행되고 있는 상태를 뜻한다.
- Program은 하드 디스크에서 실행을 기다리고 있는 코드, 또는 실행 파일이다.
- OS로 부터 할당받아 실행된다.
Thread?
- 하나의 Process내에서 실행되는 하나의 작업 단위이다.
- 메모리와 IO 장치 및 컴퓨터 자원들을 공유한다.
둘의 관계?
- 애플리케이션이 실행될 때 하나의 Process가 발생한다.
- 해당 Process가 어떠한 작업을 수행할 떄 컴퓨터 자원을 최대한 활용하기 위해 작업을 병렬로 수행해야 한다.
- Thread를 이용해서 컴퓨터의 놀고 있는 자원을 최대한 사용하게 한다.
- 이를 Multi-Thread Programming이라 한다.
- IO를 기다리게 하지 않고 다른 일을 하게 하거나, 놀고 있는 여분의 CPU 코어들을 최대한 사용하게 하는 것이 핵심이다.
그렇다면 동시성과 병행성은 무엇일까?
Parallelism
language에서 Parallelism이라 불리는 대표적인 예가 Thread 이다. Thread는 그야말로 동시에 평행적으로 실행 된다.
Concurrency
Concurrency는 Parallelism의 난해함을 풀어낸 방법이다. 대표적인 예로 Coroutine이 있다.
Coroutine이란?
- 유니티에서 코루틴은 서브루틴의 일종으로 진입시점이 여러개인 서브루틴을 말한다.
- 특정 라인이 수행된 다음 차근차근 수행되는 Sync 방식이 아니라 Async하게 코드를 실행시키고, 결과 값이 오거나 혹은 필요한 때에 다음 루틴을 실행 시키게 할 수 있어서 효율적으로 자원을 활용할 수 있다. 덤으로 코드가 Thread로 구현했을 때보다 훨씬 깔끔하게 나오고, Locking/UnLocking 메커니즘을 싹 걷어낼 수 있게 된다.
Concurrency의 개념을 적극적으로 도입한 Go Language
package main
import "fmt"
func f(from string) {
for i := 0; i < 10; i++ {
fmt.Println(from, ":", i)
}
}
func main() {
f("direct")
go f("goroutine")
go func(msg string) {
fmt.Println(msg)
}("going")
var input string
fmt.Scanln(&input)
fmt.Println("done")
}
Go 언어에서 Concurrency의 개념은 Goroutine으로 구현되어있다.
Goroutine은 multi-thread의 백단 dirty한 부분에 손 하나 대지 않고 쉽게 Async한 일들을 처리할 수 있게 해준다.
Goroutine은 자원을 Locking/Unlocking하는 코드들이 불필요하다.
아랫단의 일들을 golang의 runtime이 알아서 해주고 Thread를 여러개 실행 시키도록 셋팅하면 각 thread에 goroutine을 할당하여 자원을 관리하는 일까지도 언어단에서 알아서 해준다.
개발자들은 C/C++에서 thread를 사용하는 것과 마찬가지로 적절한 작업들에 goroutine을 호출시키고 channel을 이용해서 결과값들을 받아서 훨씬 수월하게 처리할 수 있다.
이러한 언어의 Concurrency는 기존에 C나 C++에서 다루었었던 멀티쓰레드와 자원 관리의 복잡함으로부터 개발자들을 해방시키는 역할을 해준다.
동시에 Multi-Thread로 해냈던 수준의 Async하고 parallel한 작업들을 흉내내거나 손쉽게 수행할 수 있도록 해준다.