코루틴

황승현·2023년 12월 7일
0

코틀린 강의 정리

목록 보기
36/36
post-thumbnail

코루틴

경량화된 비동기 기능 제공

  • 최적화비동기 함수를 사용

  • 하드웨어 자원의 효율적인 할당 가능

  • 안정적인 동시성, 비동기 프로그래밍이 가능

  • 코루틴은 하나의 Thread를 잘개 쪼개서 사용하기 때문에 CPU 자원을 절약할 수 있어서 Light-Weight Thread라고도 불린다.

  • 하나의 쓰레드에서 여러 개의 코루틴 사용 가능

  • 작업 하나하나의 단위 : 코루틴 객체 (Coroutine Object)

    • 여러 작업 각각에 객체(Object)를 할당
    • 메모리의 특정 영역인 JVM Heap에 코루틴 객체를 저장 (Stack에 별도 영역을 만들지 않는다.)

Programmer Switching (No-Context Switching)

OS의 관여 없이 소스코드를 통해 Switching 시점을 마음대로 정해, 동시성을 보장한다.

다시 말해 운영체제 커널의 스케줄링을 따르는 Context Switching을 수행하지 않는다.

Suspend (Non-Blocking)

  • Object 1이 Object 2의 결과를 기다릴 때 Object 1의 상태는 Suspend로 바뀌어요
  • 그래도 Object 1을 수행하던 **Thread는 그대로 유효해요**
  • 그래서 Object 2도 Object 1과 동일한 Thread에서 실행되어요

  • Coroutine은 작업 단위가 Object라고 했어요
  • Task 1을 수행하다가 Task 2의 수행요청이 발생했다고 가정해볼게요
  • 신기하게도 컨텍스트 스위칭 없이 동일한 Thread A에서 수행할 수 있어요
  • Thread C처럼 하나의 쓰레드에서 여러 Task Object들을 동시에 수행할 수 있어요
  • 이러한 특징때문에 코루틴을 Light-Weight Thread라고 이야기해요

코루틴 빌더(Builder)

launch (결과값이 없는 코루틴 빌더)

결과값을 반환할 필요가 없을 때 사용한다.

다양한 함수를 가진 Job객체로 코루틴을 관리

  • join: 현재의 코루틴이 종료되기를 기다림

  • cancel: 현재의 코루틴을 즉시 종료

async (결과값이 있는 코루틴 빌더)

결과값을 반환할 필요가 있을 때 사용한다.

코루틴 범위 지정(Scope)

GlobalScope (계속 실행해야할 때 사용)

  • 앱이 실행된 후 계속 수행되어야 할 때 사용

CoroutineScope (필요할 때만 코루틴 객체 생성, 사용 후 할당 해제 필요)

  • 필요할때만 코루틴 객체 생성

  • 사용 후에 정리해야 됨(할당을 해제해야 됨)

Dispatcher

하나의 쓰레드 안에서 코루틴을 여러개 쓰는 것

코루틴을 실행할 쓰레드를 Dispatcher로 지정할 수 있다.

예제

메인 쓰레드가 먼저 끝나기 때문에 코루틴 결과를 출력 못하는 상황

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch


// main 함수 = 메인 쓰레드
fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    
    // GlobalScope = 앱이 실행된 후 계속 수행되어야 할 때 사용
    // launch = 결과값이 없는 코루틴 빌더
    var job = GlobalScope.launch {
        delay(3000) //3초 딜레이
        println("여기는 코루틴...")
    }
    
    //메인 쓰레드가 끝나서 코루틴도 끝남
    println("메인쓰레드 종료") //코루틴은 3초동안 딜레이를 줄려고 했는데 메인 쓰레드가 먼저 끝나버림
}

메인 쓰레드와 비동기적으로 코루틴 결과를 출력하는 방법 (GlobalScope 사용)

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

// main 함수 = 메인 쓰레드
fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    
    // GlobalScope = 앱이 실행된 후 계속 수행되어야 할 때 사용
    // launch = 결과값이 없는 코루틴 빌더
    var job = GlobalScope.launch {
        delay(3000) //3초 딜레이
        println("여기는 코루틴...")
    }
    
    // 괄호 안의 내용이 끝날 때까지 기다리겠다.
    runBlocking {
        job.join() //현재의 코루틴이 종료되기를 기다림
    }
    
    // 코루틴이 끝나고 나서, 메인쓰레드가 종료됨
    println("메인쓰레드 종료")
}

메인 쓰레드와 비동기적으로 코루틴 결과를 출력하는 방법 (CoroutineScope 사용)

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

// main 함수 = 메인 쓰레드
fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    
    // CoroutineScope = 필요할 때만 코루틴 생성
    // launch = 결과값이 없는 코루틴 빌더
    // Dispatchers.Default = CPU에 최적화되어있는 쓰레드
    var job = CoroutineScope(Dispatchers.Default).launch {
        delay(3000)
        println("여기는 코루틴...")
    }
    
    // 괄호 안의 내용이 끝날 때까지 기다리겠다.
    runBlocking {
        job.join() //현재의 코루틴이 종료되기를 기다림
    }
    
    // 코루틴이 끝나고 나서, 메인쓰레드가 종료됨
    println("메인쓰레드 종료")
    
    // CoroutineScope로 만든 job 객체는 사용 후에 할당을 해제해야 됨
    job.cancel()
}

코투린 여러 개 사용 예시

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking


// main 함수 = 메인 쓰레드
fun main(args: Array<String>) {
    println("메인쓰레드 시작")
    
    // CoroutineScope = 필요할 때만 코루틴 생성
    // launch = 결과값이 없는 코루틴 빌더
    // Dispatchers.Default = CPU에 최적화되어있는 쓰레드
    var job = CoroutineScope(Dispatchers.Default).launch {
    
    	// async = 결과값을 반환할 필요가 있을 때 사용
        // Dispatchers.IO = 네트워크나 디스크 I/O작업에 최적화되어있는 쓰레드
        var fileDownloadCoroutine = async(Dispatchers.IO) { //파일 다운로드 할 때 사용할 코루틴
            delay(10000) //10초 딜레이
            "파일 다운로드 완료"
        }
        
        // async = 결과값을 반환할 필요가 있을 때 사용
        // Dispatchers.IO = 네트워크나 디스크 I/O작업에 최적화되어있는 쓰레드
        var databaseConnectCoroutine = async(Dispatchers.IO) { //파일 데이터베이스에 넣을 때 사용할 코루틴
            delay(5000) //5초 딜레이
            "데이터베이스 연결 완료"
        }
        println("${fileDownloadCoroutine.await()}") // await() = 일시중지가 가능한 코루틴에서 사용
        println("${databaseConnectCoroutine.await()}") // await() = 일시중지가 가능한 코루틴에서 사용
    }
    
    // 괄호 안의 내용이 끝날 때까지 기다리겠다.
    runBlocking {
        job.join() //현재의 코루틴이 종료되기를 기다림
    }
    
    // 코루틴이 끝나고 나서, 메인쓰레드가 종료됨
    println("메인쓰레드 종료")
    
    // CoroutineScope로 만든 job 객체는 사용 후에 할당을 해제해야 됨
    job.cancel()
}

참고자료

https://kotlinlang.org/docs/coroutines-basics.html#your-first-coroutine
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://noapps-code.tistory.com/98

0개의 댓글