App노자

[Kotlin] Coroutines (launch, async) 본문

Android/Kotlin

[Kotlin] Coroutines (launch, async)

앱의노예 2023. 9. 5. 20:12

1. Coroutines이란?


코루틴은 동시성 및 병렬성을 다루기 위한 프로그래밍 패턴과 기술이다

Kotlin은 다른 라이브러리가 코루틴을 활용할 수 있도록 표준 라이브러리에 최소한의 하위 수준 API만 제공한다

코루틴은 비동기 프로그래밍을 보다 쉽게 다룰 수 있게 해 주며, 다른 스레드를 생성하거나 관리하는 것보다 가벼우면서도 효율적인 방식으로 비동기 코드를 작성할 수 있게 해 준다

 

https://kotlinlang.org/docs/coroutines-overview.html

 

Coroutines | Kotlin

 

kotlinlang.org

2. build.gradle (Module)


dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0"
}

build.gradle(Module: app)의 dependencies안에 코루틴을 사용할 수 있게 위의 내용을 작성한다

3. launch


fun main() {  // 메인 스레드
    GlobalScope.launch { // 새로운 코루틴을 백그라운드에 실행
        //delay(1000L) // 1초의 넌블로킹 지연 (시간의 기본단위는 ms)
        Thread.sleep(1000L)
        println("World!") // 지연 후 출력
        doSomething()
    }
    println("Hello,") // main 스레드가 코루틴이 지연되는 동안 계속 실행된다.
    Thread.sleep(2000L) // main스레드가 JVM에서 바로 종료되지 않게 2초 기다린다.
    //delay(2000L)
}

suspend fun doSomething() {
    println("Do something!")
}

launch 함수를 사용하면 비동기 작업을 실행하고 결과를 기다리지 않고 다른 작업을 계속할 수 있다

이 함수는 비동기 작업을 백그라운드에서 실행하고 결과가 필요하지 않은 경우에 사용된다

위의 코드에서 main() 함수의 블록은 메인 스레드로서 작동하게 되고

코루틴 코드는 메인 스레드와 분리되어 백그라운드에서 1초 뒤에 실행된다 

코루틴에서 사용되는 함수는 suspend()로 선언된 지연 함수여야 코루틴 기능을 사용할 수 있다

컴파일러는 suspend가 붙은 함수를 자동적으로 Continuation 클래스부터 분리된 루틴을 만든다

suspend로 표기함으로써 이 함수는 실행이 일시 중단 될 수 있으며 필요한 경우에 다시 재개할 수 있게 된다

// 순차적 실행

suspend fun doWork1(): String {
    delay(1000)
    return "Work1"
}

suspend fun doWork2(): String {
    delay(3000)
    return "Work2"
}

private fun worksInSerial() {
    // 순차적 실행
    GlobalScope.launch {
        val one = doWork1()
        val two = doWork2()
        println("Kotlin One : $one")
        println("Kotlin Two : $two")
    }
}

fun main() {
    worksInSerial()
    readLine()
}

suspend 키워드를 사용한 2개의 함수 doWork1()과 doWork2()를 정의하고 그 안에 delay() 작성했다

launch에 정의된 doWork1()과 doWork2() 함수를 순차적으로 표현함으로써 프로그래밍의 복잡도를 낮출 수 있다

4. Job 객체


// Job 객체의 반환

fun main() {
    val job = GlobalScope.launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    println("job.isActive: ${job.isActive}, completed: ${job.isCompleted}")
    Thread.sleep(2000L)
    println("job.isActive: ${job.isActive}, completed: ${job.isCompleted}")
}
job.join(): job 객체의 join 메서드를 호출하여 코루틴이 완료될 때까지 대기할 수 있다
이 메서드는 코루틴이 완료되기를 기다리는 동안 현재 스레드를 차단한다

job.cancel(): job 객체의 cancel 메서드를 호출하여 코루틴을 취소할 수 있다
이렇게 하면 코루틴의 실행이 중단되고 취소 상태가 된다

job.isCompleted: job 객체의 isCompleted 속성을 사용하여 코루틴이 완료되었는지 여부를 확인할 수 있다

job.isActive: job 객체의 isActive 속성을 사용하여 코루틴이 현재 실행 중인지 여부를 확인할 수 있다

job.isCancelled: job 객체의 isCancelled 속성을 사용하여 코루틴이 취소되었는지 여부를 확인할 수 있다

launch로 시작한 코루틴은 현재 스레드를 차단하지 않고 새로운 코루틴을 실행할 수 있게 한다

launch 코루틴 빌더를 사용하여 코루틴을 생성하면 Job 객체가 반환되는데

코루틴에서 Job 객체는 코루틴의 실행을 관리하고 제어하는 데 사용되는 중요한 개체이다

위의 코드에서 launch는 GlobalScope가 지정되어 있어 코루틴의 생명 주기가 프로그램 생명 주기에 의존된다

코루틴을 실행하기 위해서는 내부적으로 스레드를 통해서 실행될 수 있으며 실행 루틴이 많지 않을 경우 하나의 스레드에서 여러 개의 코루틴을 실행할 수 있다

5. async


suspend fun doWork1(): String {
    delay(1000)
    return "Work1"
}

suspend fun doWork2(): String {
    delay(3000)
    return "Work2"
}

private fun worksInParallel() {
    // Deferred<T> 를 통해 결과값을 반환
    val one = GlobalScope.async {
        doWork1()
    }
    val two = GlobalScope.async {
        doWork2()
    }

    GlobalScope.launch {
        val combined = one.await() + "_" + two.await()
        println("Kotlin Combined : $combined")
    }
}


fun main() {
    worksInParallel()
    readLine()
}

async는 코루틴에서 사용되는 빌더 중 하나로, 비동기 작업을 수행하고 결과를 반환하는 데 사용된다

async도 새로운 코루틴을 실행할 수 있는데 Deferred<T>을 통해 launch와는 다르게 결과를 반환하므로

작업이 완료되었을 때 그 결과를 사용하거나 처리할 수 있다

복잡한 루틴을 작성하는 경우에는 많은 태스크들과 같이 병행 수행되므로 어떤 루틴이 먼저 종료될지 알기 어렵다

태스크가 종료되는 시점을 기다렸다가 지연된 결괏값을 받기 위해 await()을 사용하는데 현재 스레드의 블로킹 없이 먼저 종료되면 결과를 가져올 수 있다

'Android > Kotlin' 카테고리의 다른 글

[Kotlin] 프로세스와 스레드  (0) 2023.08.20
[Kotlin] object 키워드  (0) 2023.08.15
[Kotlin] Closure (클로저)  (0) 2023.08.10
[Kotlin] 코틀린 표준 라이브러리  (0) 2023.08.09
[Kotlin] by 키워드  (0) 2023.08.06