프로젝트를 진행하다보면 비동기 처리를 위해 사용되는 라이브러리들이 많은데 비동기처리의 주 "코루틴" 에 대해서 공부하다보니, thread? coroutine? 비슷한 작동방식이 아닌가라는 생각이 들었다.
그래서 쓰레드와 코루틴이 정확히 무엇인지 비교를 해보려고 한다.
먼저 Thread와 Coroutine은 모두 동시성 프로그래밍을 위한 기술이다.
동시성과 병렬성(Concurrency & Parallelism)
동시성 (Concurrency)
말 그대로 동시에 여러 작업을 수행하는 것
Task1과 Task2를 시분할(Interleaving) 기법을 활용하여 동시에 실행되는 것처럼 번갈아가며 수행한다.
수행시간은 Task1이 걸리는 시간 10분 + Task2가 걸리는 시간 10분 = 총 20분이 소요된다.
병렬성 (Parallelism)
여러 작업을 한 번에 동시에 수행하는 것 병렬성은 '자원(CPU 코어)이 여러 개' 일 때 가능
동시성과 달리 하나의 CPU 코어에서 Task들이 실행되는 것이 아니라 각 Task는 각 CPU에 배분되어 병렬적으로 동시에 수행된다.
따라서 각 Task들은 10분씩 걸린다고 가정하였으므로 수행시간은 총 10분이 소요된다.
💡 Thread vs Coroutine
Thread는 각 태스크에 해당하는 스택 메모리를 할당받는다.
그리고여러 작업을 동시에 수행해야할 때 OS 는어떤 쓰레드 작업을 먼저 수행할지,어떤 쓰레드를 더 많이 수행해야효율적인지에 대한스케쥴링(선점 스케쥴링) 을 해야 한다.
Coroutuine은Lightweight Thread라고 부른다.
마찬가지로 작업 하나하나를 효율적으로 분배해서 동시성을 보장하는 것을 목표로 하지만, 작업 하나하나에 Thread 를 할당하는 것이 아닌 '객체' 를 할당해주고, 이 객체를 자유롭게 스위칭함으로써 Context Switching 비용을 대폭 줄인 것이다.
Thread
1. 작업(Task) 하나하나의 단위 :Thread
각 Thread 가 독립적인Stack 메모리 영역가짐
2. 동시성 보장 수단 :Context Switching
운영체제 커널에 의한Context Switching을 통해 동시성 보장
블로킹(Blocking) : Thread A 가 Thread B 의결과가 나오기까지 기다려야 한다면, Thread A 은블로킹되어 Thread B 의결과가 나올 때 까지 해당 자원을 못 씀
Thread A에서Task 1 을 수행하다가Task 2 의 결과가 필요할 때, 비동기적으로Thread B 를 호출을 하게 된다. 이 때Thread A 는 블로킹되고,Thread B 로 Context Switching이 일어나Task 2를 수행한다.Task 2 가 완료되면, 다시Thread A 로 Context Switching이 일어나 결과값을Task 1에 반환한다.
동시에 같이 수행할Task 3, Task 4는 각각Thread C 와 D에할당되고, 총체적으로 봤을 때 커널 입장에서Preempting Scheduling을 통하여각 태스크를 얼만큼 수행할지, 혹은 무엇을 먼저 수행할지를 결정하여 알맞게동시성을 보장하게 되는 것이다.
Coroutine
1. 작업 하나하나의 단위 :Coroutine Object
여러 작업 각각에 Object 를 할당함
Coroutine Object 도 엄연한 객체이기 때문에JVM Heap 에 적재됨 (코틀린 기준)
Suspend(Non-Blocking) : Object 1 이 Object 2 의결과가 나오기까지 기다려야 한다면, Object 1 은Suspend(중단)되지만, Object 1 을 수행하던Thread 는 그대로 유효하기때문에 Object 2 도 Object 1 과동일한 Thread 에서 실행될 수 있음
작업 단위는Coroutine Object이므로,Task 1 을 수행하다가비동기 작업 Task 2 가 발생하더라도,Context Switching 없이같은 Thread 에서 Task 2 를 수행할 수 있고, 맨 오른쪽 경우처럼하나의 Thread 에서 여러 Coroutine Object 들을 같이 수행할 수도 있다.한 쓰레드에서 다수의 Coroutine 을 수행할 수 있고,Context Switching 이 필요없는 특성에 따라Coroutine 을 Light-weight Thread 라고 부르는 것이다.
(그런데 맨 오른쪽 그림처럼 Thread A 와 C 가 동시에 수행되는 모습이다. 이러면 결국동시성 보장을 위해서 Context Switching 이 필요한 경우다. 따라서,Coroutine 의 'No-Context Switching' 장점을 극강으로 끌어올리기 위해,단일 Thread 에서 여러 Coroutine Object 를 컨트롤하는 것이 좋다.)
💡 Coroutine 은 Thread 의 대안이 아니라, Thread 를 더 잘게 쪼개어 사용하기 위한 개념이다.
작업의 단위를Object로 축소하면서 하나의Thread가 다수의 코루틴을 다룰 수 있기 때문에,작업 하나하나에 Thread 를 할당하며메모리 낭비, Context Switching 비용 낭비를 할 필요가 없음