오늘도 더 나은 코드를 작성하였습니까?

coroutine basics(코루틴의 기초 공식문서 번역 설명) 본문

Coroutine/coroutineBasic

coroutine basics(코루틴의 기초 공식문서 번역 설명)

hik14 2022. 6. 29. 14:16

* 배경지식

 

process (프로세스)

- 실행중인 응용프로그램() 인스턴스이다, 어플리케이션은 여러개의 프로세스로 구성될 수 있다.

- 운영체제로부터 자원(메모리, CPU, 네트워크 등)을 할당받은 작업의 단위

 

thread(쓰레드)

- 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위.

- 스레드(thread)란 프로세스(process) 내에서 실제로 작업을 수행하는 주체

- 모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행

 

coroutine(코루틴)

- 일시적으로 중단 가능한 코드 블록.

- 동시에 작동하는 코드 블록을 실행하다는점은 Thread와 유사하다 

- coroutine은 특정 스레드에서 실행되는 것이 아니라, 특정 쓰레드에서 실행되다 중단되고 다시 이전 쓰레드와 다른 쓰레드에서 실행 가능
- 코루틴은 경량 스레드로 생각할 수 있지만, 실제 사용에 있어서 차이점이 많다

 

첫번째 코루틴

fun main() = runBlocking { // this: CoroutineScope
    launch { 
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello") // main coroutine continues while a previous one is delayed
}

launch

- 코루틴 Builder 중 하나이다.

- 독립적으로 계속 작동하는 나머지 코드와 동시에 새 코루틴을 시작.

 

delay

- 특별한 suspend function.

- 특정 시간 동안 코루틴을 일시 중단.

- 코루틴을 일시 중단하면 기본 스레드가 차단되지 않지만 다른 코루틴이 실행되고 코드에 기본 스레드를 사용할 수 있습니다.

 

runBlocking { ... }

- 블록안에 새 코루틴을 실행하고 완료될때 까지 현재 쓰레드를 차단한다. 

- 다른 코루틴 블록내에서 사용하면 안된다.

-  suspending style로 작성된 라이브러리의 주요 기능 및 테스트에 사용 하기 위해 만듬.

- 일반 fun main()의 비코루틴 세계와 runBlocking { ... } 중괄호 내부의 코루틴이 있는 코드를 연결하는 코루틴 Builder

Structured concurrency ( 구조화된 동시성)

코루틴은 구조화된 동시성의 원칙을 따른다.

즉, 새로운 코루틴은 코루틴의 수명을 제한하는 특정 CoroutineScope에서만 시작될 수 있다

 

- coroutines은 손실되지 않고 누출되지 않도록 합니다.

- 외부 범위는 모든 하위 코루틴이 완료될 때까지 완료할 수 없습니다

1. {

   2. launch { ... }

   3. launch { ....

                      4. launch { ... }

                 }

}

4번이 끝나야 3번이 끝나고,  2, 3끝나야  1번 블록이 종료된다.

 

- 코드의 모든 error 가 적절하게 전달 되고 손실 않음.

Extract function refactoring( 함수 추출을 통한 리펙토링)

fun main() = runBlocking { // this: CoroutineScope
    launch { doWorld() }
    println("Hello")
}

// this is your first suspending function
suspend fun doWorld() {
    delay(1000L)
    println("World!")
}

suspend 붙혀서 새 함수를 생성한다.

suspend 함수는 일반 함수와 마찬가지로 코루틴 내부에서 사용할 수 있지만, 차이점은 순차로 다른 suspend 함수(delay)을 사용하여 코루틴 실행을 일시 중단할 수 있다.

 

Scope builder

기본 제공하는 코루틴 scope 외에도 coroutineScope 빌더를 사용하여 고유한 범위를 선언할 수 있다.

coroutineScope를 만들고 실행된 모든 자식이 완료될 때까지 완료되지 않습니다.

 

runBlocking 및 coroutineScope 빌더는 모두 본 블록과 모든 하위 코루틴이 완료될 때까지 기다리기 때문에 비슷해 보일 수 있다.

차이점은 runBlocking 메서드는 대기를 위해 현재 스레드를 차단하는 반면 coroutineScope는 suspend(중단)하여 다른 일을 위해 스레드를 이용한다. 

public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {

}

public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R {

}

Scope builder and concurrency

coroutineScope 빌더는  suspend function 안에서 여러 동시 작업을 수행하는 데 사용할 수 있습니다.

// Sequentially executes doWorld followed by "Done"
fun main() = runBlocking {
    doWorld()
    println("Done")
}

// Concurrently executes both sections
suspend fun doWorld() = coroutineScope { // this: CoroutineScope
    launch {
        delay(2000L)
        println("World 2")
    }
    launch {
        delay(1000L)
        println("World 1")
    }
    println("Hello")
}

launch { ... } 블록 내부의 두 코드는 동시에 실행

An explicit job (명시 작업)

launch 코루틴 빌더는 시작된 코루틴에 대한 job 개체를 반환하고 명시적으로 완료를 기다리는 데 사용할 수 있다.

예를 들어, 자식 코루틴이 완료될 때까지 기다린 다음 "Done" 문자열을 인쇄할 수 있습니다.

val job = launch { // launch a new coroutine and keep a reference to its Job
    delay(1000L)
    println("World!")
}
println("Hello")
job.join() // wait until child coroutine completes
println("Done")

 

Coroutines are light-weight

코루틴은 JVM Thread 보다 리소스 집약적입니다. 

스레드를 사용할 때 JVM의 가용 메모리를 소모하는 코드는 리소스 제한에 도달하지 않고 코루틴을 사용하여 표현할 수 있습니다. 

예를 들어, 다음 코드는 각각 5초를 기다린 다음 매우 적은 메모리를 소비하면서 마침표('.')를 인쇄하는 100000개의 고유한 코루틴을 시작합니다.

import kotlinx.coroutines.*

fun main() = runBlocking {
    repeat(100_000) { // launch a lot of coroutines
        launch {
            delay(5000L)
            print(".")
        }
    }
}

스레드를 사용하여 동일한 프로그램을 작성하는 경우(runBlocking 제거, 시작을 스레드로 교체, 지연을 Thread.sleep으로 교체) 메모리를 너무 많이 소비하고 메모리 부족 오류가 발생할 수 있습니다.

 

'Coroutine > coroutineBasic' 카테고리의 다른 글

Coroutine scope  (0) 2022.07.07
Coroutine context and dispatchers  (0) 2022.07.06
Composing suspending functions (suspend 함수 구성하기)  (0) 2022.07.05
Cancellation and timeouts  (0) 2022.07.05