CS/Android

Coroutine (1)

졔졔311 2024. 12. 17. 15:47
728x90
반응형

ㅇ coroutine이란?

- 실행을 일시 중단(suspend)/다시 실행(resume) 시킬 수 있는 기술

- 비동기 프로그래밍을 위해 사용되기 때문에, 개념적으로는 일종의 경량 스레드(light-weight thread)로 볼 수 있지만, 특정 thread에 종속되지 않기 때문에 실질적으로는 매우 다름

- 안드로이드 개발에서는 UI thread는 유지하면서 네트워크 호출, 파일 입출력, DB 작업 등의 비동기 작업을 효율적으로 처리하기 위해 많이 사용

 

ㅇ coroutine의 장점

1. 비동기 작업 처리

- 시간이 많이 걸리는 비동기 작업을 메인 thread와 별도 thread에서 처리하여 효율적

- main thread에서 사용할 경우 ANR(Application Not Responding)이 발생할 수 있다.

 

2. UI와의 자연스러운 상호작용

- 안드로이드 앱은 UI 업데이트를 반드시 main thread에서 처리해야 한다.

- coroutine을 사용하면 Dispatchers.Main을 통해 UI를 안전하게 처리 가능

 

3. 경량성

- thread보다 훨씬 가볍기 때문에 메모리 사용량이 적고 context switching 비용이 낮다.

 

ㅇ 주요 요소

CoroutineScope

- coroutine의 실행 범위를 정의하는 컨테이너

- 안드로이드에서는 주로 lifecycleScope, viewModelScope와 같은 구조화된 coroutine scope를 활용

 

Dispatcher

- coroutine이 실행되는 thread나 context를 지정

- 종류

  • Dispatchers.Main : 안드로이드의 메인(UI) thread에서 실행
  • Dispatchers.IO : 입출력 작업(파일, 네트워크, DB)에 최적화
  • Dispatchers.Default : CPU 집중 작업에 적합
  • Dispatchers.Unconfined : thread에 종속x(특수한 경우에 사용)

 

Suspend 함수

- coroutine 내부에서 실행

- 비동기 작업 중 다른 coroutine의 작업을 차단하지 않고 기다릴 수 있음

- ex) delay(), withContext(), 네트워크 호출 등

 

Structured Concurrency

- coroutine은 부모-자식 관계를 가짐

- 부모 coroutine이 취소되면 자식 coroutine도 모두 취소

- 중간에 빠지거나 사라지지 않도록 보장해주고, 마찬가지로 error도 확실하게 뜰 것을 보장

 

ㅇ 실제 적용 예시

CoroutineScope 만들기

- runBlocking : non-coroutine인 fun main()과 coroutine scope(runBlocking{...})를 이어주는 coroutine builder.

실행되는 thread를 runBlock{...} 안의 모든 coroutines이 수행될 때까지 멈춤(block).

thread를 block 시키는 것은 매우 비효율적이므로 주로 top-level에서만 쓰임.

 

-  launch : coroutine builder. runBlocking과는 다르게 coroutine scope 안에서만 정의됨.

 

- delay : coroutine을 특정 시간 동안 일시 중단(suspend) 시킴. 다만, 기반 thread를 정지하는건 아니기 때문에 다른 coroutine들이 실행될 수 있음.

fun main() = runBlocking { // this: CoroutineScope
    launch { // launch a new coroutine and continue
        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
}

- 결과:

Hello
World!

 

CoroutineScope를 만드는 다른 방법

class MyClass() {    
	private val myScope = CoroutineScope(Dispatchers.IO)		// coroutine scope를 정의
    
    ...
 
    suspend fun myFunc(...) {
        try {
            ...
                    override fun myFunc1(...) {
                        myScope.launch(Dispatchers.IO) {	// 위에서 정의한 coroutine 실행                            
                            ...
                        }
                    }
 
                    override fun myFunc2(...) {
                        myScope.launch(Dispatchers.IO) {	// 위에서 정의한 coroutine 실행
                            ...
                        }
                    }
                },
            )
        } ...
    }

 

suspend 함수를 이용한 함수 분리하기

- suspend : suspending 함수를 만드는 keyword.

suspend 함수는 coroutine 안에서 일반 함수처럼 사용될 수 있음

delay와 같은 다른 suspending 함수를 사용할 수 있음

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

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

 

 

 

출처 : Coroutines basics | Kotlin Documentation

728x90
반응형

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

Build Variant  (1) 2024.12.26
Coroutine (2)  (0) 2024.12.24
공통 객체 이용하기 - CompositionLocal  (0) 2024.12.17
Navigation  (0) 2024.12.16
Composable & Preview  (0) 2024.12.13