[Tistory] [Kotlin] 코루틴 찍먹

원글 페이지 : 바로가기

스레드와 코루틴 스레드 Thread 클래스의 인스턴스는 프로그램이 실행될 때 운영체제의 네이티브 스레드를 나타낸다. 스레드(Thread)의 각 인스턴스는 해당 스택에 대한 메모리를 사용하고 초기화하기 위한 시간이 필요하다. 스레드의 컨텍스트 전환은 꽤 비싼 작업이기 때문에 별도의 스레드에서 짧은 작업을 호출하는 것은 좋은 결과를 가져오기 어렵다. 코루틴 (CoRoutine) 코루틴은 힙 메모리의 객체를 의미하며 코루틴 간의 전환은 운영체제 커널 작업이 아니다. 코루틴은 프로세스에 할당된 힙 메모리 영역을 공유해서 사용한다. 즉, 스레드에 비해 빠르고 적은 비용으로 생성할 수 있으며 자원도 적게 사용된다. 간단 사용법 코루틴은 CoroutineContext 인터페이스로 표시되는 컨텍스트에서 실행된다. Element 인터페이스는 CoroutineContext를 상속받는다. 주요 요소는 Job 및 CoroutineDispatcher 클래스의 인스턴스이다. 코루틴은 일반적인 스레드를 사용하고 CoroutineDispatcher는 코루틴에서 어떤 스레드를 사용할지 선택한다. CoroutineDispatcher는 가용성, 부하, 설정을 기반으로 스레드간에 코루틴을 분산하는 오케스트레이터이다. launch 함수는 Element 인터페이스를 구현하고 코루틴의 실행을 취소하는 데 사용할 수 있는 Job 클래스의 인스턴스를 반환한다. fun main(args: Array) = runBlocking { // coroutine scope
val job = launch {
delay(500L)
println(Thread.currentThread().name)
}
println(Thread.currentThread().name)
job.join() // 스코프 내 모든 코루틴 동작이 끝날 때 까지 대기
} CoroutineScope 에서 코루틴을 시작할 수 있다. CoroutineScope 라는 컨테스트에서 코루틴 빌더를 통해 새로운 코루틴을 만들 수 있다. runBlocking, async, launch 가 코루틴 빌더이며 CoroutineScope의 확장 함수이다. async, launch : 현재 스레드를 블락하지 않고 새로운 코루틴을 실행 async : 결과값을 반환받고 싶은 경우 사용 (Deferred 인스턴스를 돌려주고 await() 메서드를 통해 계산 결과에 접근할 수 있음) launch : 동시성 작업이 결과를 만들어 내지 않는 경우 적합 (연산이 실패한 경우에만 통보를 받기 위함) runBlocking : 현재 스레드를 블락하고 새로운 코루틴을 실행 새 코루틴을 실행하고 완료될 때까지 현재 스레드를 blocking 시키기 때문에, coroutine 목적과 맞지 않으며 사용을 지양 async 를 활용한 동시성 프로그래밍 fun main(args: Array) = runBlocking { // Coroutine Scope
val time = measureTimeMillis {
val card = async { loadCardInfo() }
val user = async { loadUserInfo() }
println(“card : ${card.await()}, user : ${user.await()}”) // Deferred(지연)되는 값을 받는다.
}

println(“Completed in $time ms”)
}

suspend fun loadCardInfo(): String {
delay(1000L)
return “카드 정보를 조회하였습니다.”
}

suspend fun loadUserInfo(): String {
delay(1000L)
return “사용자 정보를 조회하였습니다.”
} 순차 실행을 한다면 2초가 걸리지만 async를 활용하면 1초로 처리할 수 있다. CoroutineScope CoroutineScope는 기본적으로 CoroutineContext 하나만 멤버 속성으로 정의하고 있는 인터페이스 public interface CoroutineScope {
public val coroutineContext: CoroutineContext
} 모든 코루틴 빌더들은 CoroutineScope의 확장 함수로 정의회어 CoroutineScope에 정의된 CoroutineContext를 기반으로 필요한 코루틴이 생성이 된다. 코루틴 빌더 : launch, scope 스코프 빌더 : coroutineScope, withContext GlboalScope 어디에도 속하지 않은 전역적인 Scope 간편하게 코루틴을 생성하고 사용할 수 있는 장점이 있으나 계층적으로 관리되지 않아 관리가 어렵다는 단점이 있음 fun main(args: Array) {
GlobalScope.launch {
val time = measureTimeMillis {
val card = async { loadCardInfo() }
val user = async { loadUserInfo() }
println(“card : ${card.await()}, user : ${user.await()}”)
}

println(“Completed in $time ms. ${Thread.currentThread().name}”)
}
Thread.sleep(2000)
println(“Main End. ${Thread.currentThread().name}”)
} CoroutineScope 계층적으로 형성된 코루틴을 관리할 수 있다. GlobalScope를 대체하여 CoroutineScope를 이용하는 것이 좋다. CoroutineContext를 파라미터로 받아 커스텀한 Scope를 만들 수 있으며 GlobalScope를 대체하여 사용하는 것이 좋다. fun main(args: Array) {
CoroutineScope(Dispatchers.IO).launch {
val time = measureTimeMillis {
val card = async { loadCardInfo() }
val user = async { loadUserInfo() }
println(“card : ${card.await()}, user : ${user.await()}”)
}

println(“Completed in $time ms. ${Thread.currentThread().name}”)
}
Thread.sleep(2000)
println(“Main End. ${Thread.currentThread().name}”)
} 참고 https://wooooooak.github.io/kotlin/2019/08/25/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EA%B0%9C%EB%85%90-%EC%9D%B5%ED%9E%88%EA%B8%B0/ https://velog.io/@jshme/kotlin-coroutines-basic https://jslee-tech.tistory.com/57?category=1058609

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다