[Kotlin] Thread와 Coroutine

Subeen·2023년 12월 11일
0

Kotlin 문법

목록 보기
16/23

비동기 프로그래밍

  • 비동기 프로그래밍이란 여러가지의 로직들이 완료 여부에 관계 없이 실행되는 방식을 의미한다.
  • 비동기 프로그래밍은 요청을 보내고 결과 값을 받을 때까지 멈추지 않고 다른 일을 수행한다.
    • 동기 프로그래밍은 요청을 보내고 결과 값을 받을 때까지 작업을 멈춘다.

Thread

  • Thread는 로직을 동시에 실행할 수 있도록 도와준다.
fun main() {
    thread(start = true) {
        for (i in 1..5) {
            println("Thread1 : ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }

    thread(start = true) {
        for (i in 50..55) {
            println("Thread2 : ${i}")
            runBlocking {
                launch {
                    delay(1000)
                }
            }
        }
    }
}
  • 실행 결과
Thread1 : 1
Thread2 : 50
Thread2 : 51
Thread1 : 2
Thread1 : 3
Thread2 : 52
Thread1 : 4
Thread2 : 53
Thread2 : 54
Thread1 : 5
Thread2 : 55

Coroutine

  • 코루틴(Coroutine)은 빌더와 함께 사용한다.

    • launchasync 빌더를 가장 많이 사용한다.

      launch는 결과 값이 없는 코루틴 빌더를 의미한다. Job 객체를 바놘하며 이를 통해 상태를 관리한다.
      async는 결과 값이 있는 코루틴 빌더를 의미한다. Deferred 타입으로 값을 반환하며 이를 통해 상태 관리와 결과 값에 접근할 수 있다. 결과 값은 await() 함수를 통해 접근할 수 있다.

  • 코루틴은 스코프로 범위를 지정할 수 있다.

    GlobalScope : 앱이 실행 된 이후에 계속 수행 되어야 할 때 사용한다.
    CoroutineScope : 필요할 때만 생성하고 사용 후에 정리가 필요하다.

  • 코루틴을 실행 할 Thread를 Dispatcher로 지정할 수 있다.

    Dispatchers.Main : UI와 상호작용 하기 위한 메인 쓰레드
    Dispatchers.IO : 네트워크나 디스크 I/O 작업에 최적화 되어 았는 쓰레드
    Dispatchers.Default : 기본적으로 CPU 작업에 최적화 되어 있는 쓰레드

val job = GlobalScope.launch {  // 백그라운드에서 비동기적으로 수행 된다.
    delay(3000)
    println("Coroutine:: GlobalScope")
}
val job = CoroutineScope(Dispatchers.Default).launch {
    delay(3000)
    println("Coroutine:: CoroutineScope")
}
println("End Thread")
job.cancel() // 사용이 끝나면 해제 해줘야 한다.
  • await()
  • asyncDeferred 타입으로 값을 반환하며 이를 통해 상태 관리와 결과 값에 접근할 수 있다.
  • 결과 값은 await() 함수를 통해 접근할 수 있다.
fun main() {
    val job = CoroutineScope(Dispatchers.Default).launch {
        val fileDownloadCoroutine = async(Dispatchers.IO) {
            delay(10000)
            "File download completed"
        }
        val databaseConnectCoroutine = async(Dispatchers.IO) {
            delay(5000)
            "Database connection completed"
        }
        println(fileDownloadCoroutine.await())
        println(databaseConnectCoroutine.await())
    }
    println("End Main Thread")
    job.cancel()
}

Thread vs Coroutine

  • 쓰레드와 코루틴은 둘 다 동시성 프로그래밍을 위한 기술이다.
  • 동시성 프로그래밍 기술은 컨텍스트 스위칭이 중요한 개념이다.
  • 쓰레드
    • 작업 하나 하나의 단위 : Thread
      • 각 Thread가 독립적인 Stack 메모리 영역을 가진다.
    • 동시성 보장 수단 : Context Switching
      • 운영체제 커널에 의한 Context Switching을 통해 동시성을 보장한다.
    • 블로킹 (Blocking)
      • Thread A가 Thread B의 결과를 기다리고 있다.
      • 이 때 Thread A는 블로킹 상태라고 할 수 있다.
      • Thread A는 Thread B의 결과가 나올 때까지 해당 자원을 사용하지 못 한다.
  • 코루틴
    • 작업 하나 하나의 단위 : Coroutine Object
      • 여러 작업 각각에 Object를 할당한다.
      • Coroutine Object도 엄연한 객체이기 때문에 JVM Heap에 적재한다.
    • 동시성 보장 수단 : Programmer Switching (No-Context Switching)
    • 소스 코드를 통해 Switching 시점을 맘대로 정한다. (OS는 관여하지 않는다.)
    • Suspend(Non-Blocking)
      • Object 1이 Object 2의 결과를 기다릴 때 Object 1의 상태는 Suspend로 바뀐다.
      • 그래도 Object 1을 수행하던 Thread는 그대로 유효하다.
      • Object 2도 Object 1과 동일한 Thread에서 실행된다.
  • 요약
    • 쓰레드나 코루틴은 각자의 방법으로 동시성을 보장하는 기술이다.
    • 코루틴은 Thread를 대체하는 기술이 아니며 하나의 Thread를 잘개 쪼개서 사용하는 기술이다.
    • 코루틴은 쓰레드보다 CPU 자원을 절약하기 때문에 Light-Weight Thread 라고 한다.
    • 구글에서는 코루틴 사용을 적극 권장한다.
profile
개발 공부 기록 🌱

0개의 댓글