코틀린 기본 문법 - 코루틴

2024. 6. 12. 13:40[Android] Kotlin 기본 문법

# 코루틴의 개념

- 최적화된 비동기 함수를 사용

- 하드웨어 자원의 효율적인 할당을 지원

- 안정적인 동시/비동시 프로그래밍을 지원

- 쓰레드보다 가볍게 사용 가능

- 로직들을 협동해서 실행하자는 것이 목표

 

# 코루틴의 사용법

- 일반적으로 사용하는 빌더: launch 빌더, async 빌더

  1) launch - 결과값이 없는 코루틴 빌더/ Job 객체로 코루틴을 관리

  2) async - 결과값이 있는 코루틴 빌더 / Deffered 타입으로 값을 리턴

- 스코프로 코루틴의 범위를 지정할 수 있음

  1) GlobalScope: 앱이 실행된 이후에 계속 수행되어야 할 때 해당 스코프 안에서 사용

  2) CoroutineScope: 필요할 때만 생성하고 사용 후에 정리가 필요함

- 코루틴을 실행할 쓰레드를 Dispatcher로 지정할 수 있음(쓰레드 내에서 Dispatcher를 통해 코루틴을 실행)

  1) Dispatchers.Main : UI와 상호작용하기 위한 쓰레드

  2) Dispatchers.IO: 네트워크나 디스크 I/O 작업에 최적화된 쓰레드

  3) Dispatchers.Default: 기본적으로 CPU 최적화되어있는 쓰레드 

    ※ 안드로이드에서는 Dispatcher 간의 변환을 해야 하는 작업을 고려해야 함 

 

withContext

Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result. The resulting context for the block is derived by merging the current coroutineContext with the specified context using coroutineConte

kotlinlang.org

 

# 코투린 환경 체험하기

- 안드로이드는 항상 앱이 켜져있는 상태이지만, 실습환경은 실행 후 종료되는 JVM 환경임

- 따라서 실행 시 비동기 프로그래밍이 진행되지 않고, main 함수가 먼저 시작-종료되어버려 코루틴의 결과를 얻을 수 없음

fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    var job = GlobalScope.launch {
        delay(3000)
        println("여기는 코루틴...")
    }
    println("메인쓰레드 종료")
}

// 실행 결과 : 메인쓰레드 시작, 메인쓰레드 종료
// 중간의 여기는 코루틴..은 출력되지 않음.
// 백그라운드에서 비동기적으로 실행되는 부분이 메인쓰레드가 벌써 종료되어버려서 실행 자체가 안됨
// 단, 안드로이드 앱환경에서는 비동기 프로그래밍이 지원되어서 제대로 실행은 될 거임.

 

- 따라서, 실습 환경에서 비동기적으로 코루틴의 결과를 조회하기 위해 job의 join 메소드를 활용 가능

// GlobalScope 활용 예시
fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    var job = GlobalScope.launch {
        delay(3000)
        println("여기는 코루틴...")
    }
    // 끝날 때까지 기다리겠다는 것을 명시 -> 안드로이드 앱과 비슷한 비동기 프로그래밍 환경을 구현
    runBlocking {
        job.join()
    }
    println("메인쓰레드 종료")
}
// CoroutineScope 활용 예시

fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    var job = CoroutineScope(Dispatchers.Default).launch {
        delay(3000)
        println("여기는 코루틴...")
    }
    // 3초간의 딜레이 및 실행이 진행되는 동안 종료하지 않겠음을 명시
    runBlocking {
        job.join()
    }
    println("메인쓰레드 종료")
    	// CoroutineScope이므로 job.cancel()로 임의 종료시켜주기
		job.cancel()
}

 

- 여러 개의 코루틴을 사용할 수 있음

- 코루틴의 결과값을 리턴받을 수 있음

- 결과값을 리턴받기 위해 await은 일시중단이 가능한 코루틴에서 실행 가능 

	
    println("메인쓰레드 시작")
    // 비동기적으로 실행되는 부분
    var job = CoroutineScope(Dispatchers.Default).launch {
        var fileDownloadCoroutine = async(Dispatchers.IO) {
            delay(10000)
            "파일 다운로드 완료"
        }
        var databaseConnectCoroutine = async(Dispatchers.IO) {
            delay(5000)
            "데이터베이스 연결 완료"
        }
        println("${fileDownloadCoroutine.await()}")
        println("${databaseConnectCoroutine.await()}")
    }
    // 배경 작업이 끝날 때까지 기다리기
    runBlocking {
        job.join()
    }
    println("메인쓰레드 종료")
    job.cancel()