본문 바로가기

Android

Coroutine vs Thread, 코루틴, 쓰레드 차이 - 코틀린 동시성

반응형

코틀린에서 코루틴은 종종 경량 쓰레드라고 표현되며, 이러한 표현은 코루틴이 프로세서가 실행해야 하는 명령어 집합의 실행을 정의하며, 쓰레드와 비슷한 라이프사이클을 가진다는 점에서 어느 정도 알맞은 표현이라고 할 수 있습니다. 그러나 하나의 쓰레드에 두 개 이상의 코루틴이 존재할 수 있으며, 한 실행 시점에는 하나의 쓰레드에서 하나의 명령만 실행 가능합니다.

코틀린은 고정된 크기의 쓰레드 풀을 사용하고, 코루틴은 실행 시점의 상황에 따라 각 쓰레드에 배포됩니다. 이를 통해 1개의 코루틴을 생성하는 코드와 1000개의 코루틴을 생성하는 코드의 실행 시간 차이는 크게 나지 않습니다.

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

suspend fun createCoroutines(amount: Int) {
    println("Make $amount coroutine(s) threads & time count test")
    println("${Thread.activeCount()} threads active at the start")
    val time = measureTimeMillis {
        val jobs = ArrayList<Job>()
        for (i in 1..amount) {
            jobs += GlobalScope.launch {
                delay(1000)
            }
        }
        jobs.forEach {
            it.join()
        }
    }
    println("${Thread.activeCount()} threads active at the end")
    println("Took $time ms\n")
}

fun main(args: Array<String>) = runBlocking {
    createCoroutines(1)
    createCoroutines(100)
    createCoroutines(1000)
}

위 예제는 1000 ms 대기하는 n 개의 코루틴을 생성하며 생성된 쓰레드 수와 작업을 수행하는 데에 걸린 시간을 출력합니다. IntelliJ 환경에서 코드를 실행한다면 최초에 두 개의 쓰레드가 존재하는 것을 볼 수 있는데, Main Thread와 Monitor Control + Break 쓰레드라고 한다. Monitor Control + Break 쓰레드는 Control + Break를 감지하여 현재 쓰레드 정보를 Dump 한다.

코루틴은 쓰레드에 묶이지 않는다. 코루틴이 실행된 쓰레드와 코루틴이 종료된 쓰레드가 다를 수 있다는 말이다. 예제를 다음과 같이 수정하면 이를 직접 확인해볼 수 있다. 쓰레드는 한 번에 하나의 코루틴만 실행할 수 있다. 필요에 따라 프레임워크가 코루틴을 다른 쓰레드로 옮긴다.

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

suspend fun createCoroutines(amount: Int) {
    println("Make $amount coroutine(s) threads & time count test")
    println("${Thread.activeCount()} threads active at the start")
    val time = measureTimeMillis {
        val jobs = ArrayList<Job>()
        for (i in 1..amount) {
            jobs += GlobalScope.launch {
                println("Start Corountine: $i at Thread: ${Thread.currentThread().name}")
                delay(1000)
                println("Finish Corountine: $i at Thread: ${Thread.currentThread().name}")
            }
        }
        jobs.forEach {
            it.join()
        }
    }
    println("${Thread.activeCount()} threads active at the end")
    println("Took $time ms\n")
}

fun main(args: Array<String>) = runBlocking {
    createCoroutines(3)
}

코루틴은 쓰레드에 얽매이지 않는, 쓰레드보다 가볍다는 특징을 갖는다.

 
반응형