[kotlin] coroutine 입문

조갱·2023년 3월 1일
0

Coroutine

목록 보기
4/9

Coroutine 이란?

사전적 의미

co : 협력, 함께
routine : 특정한 일을 실행하기 위한 일련의 명령, 함수
즉, coRoutine 은 협력 함수 이다.

* 루틴

컴공과를 전공한 학생이라면, 서브 루틴에 대해 많이 들어봤을 것이다.
간략히 말하자면, 서브 루틴은 (코드를 재사용하기 위해) 우리가 자주 사용하는 함수(메소드)이다.

굳이 서브 루틴이라고 이름을 지은 이유가 있을 터,
반댓말로 메인 루틴도 존재한다. 시시하겠지만 그냥 메인 함수이다.
(우리가 아는 fun main() { ... } 이 맞다.)

협력 함수?

그래서 협력 함수가 무슨 말일까?

위키디피아에서 소개하기를, 코루틴은

  • 실행을 중단하고 재개하는 것을 가능하게 하는 프로그램의 구성요소이며
  • 협력형 멀티테스킹을 위한 서브루틴을 일반화한다고 한다.

Coroutines are computer program components that allow execution to be suspended and resumed, generalizing subroutines for cooperative multitasking.

즉, 코루틴은 메소드 간 협력(일시 중단하고, 재개)하면서 멀티테스킹이 가능하게 한다.

코루틴의 특징

코루틴은 Kotlin만의 기술이 아니라, 다양한 High-Level Language 에서 지원한다.
서버 사이드 (Back-End), 데스크톱, 모바일 어플리케이션 등에서 다양하게 사용되며, 주로 제어할 수 없는 대상 (IO, DB, Network) 에 사용하는게 일반적이다.

코루틴은 다음과 같은 특징을 가진다.

  • 경량 스레드
  • 협력형 멀티테스킹
  • 동시성 프로그래밍

경량 스레드

공식 문서에서 얘기하길, 코틀린은 경량 스레드(light-weight threads)라고 한다.
가장 큰 이유는, 문맥 교환 (Context-Switch) 비용이 적기 때문이다.

일반적인 스레드는 OS에서 생성/스케줄링/관리된다. 커널 모드와 유저 모드 간의 전환으로 인해 문맥 교환이 일어날 때마다 오버헤드가 발생하여 비용이 크다.

반면에, 코루틴은 Continuation객체를 통해 생성되는 실행 컨텍스트에 의해 문맥교환이 일어난다. 코루틴은 단일 스레드 내에서 여러 개의 실행 컨텍스트를 만들어서, 비동기 작업을 작은 덩어리로 분할하고, 필요한 만큼만 실행한다. 이렇게, 코루틴은 OS레벨이 아닌 응용 프로그램 내에서 실행되기 때문에 적은 비용으로 문맥 교환이 가능하다.

* 참고로, 코루틴의 중단 함수들도 각각의 TCB를 가지지만, 문맥교환은 실행중인 스레드 위에서 실행 컨텍스트 의 교체를 통해 이루어진다.

협력형 멀티테스킹

위에서 코루틴은 Continutaion 객체를 통해 생성되는 실행 컨텍스트에 의해 문맥교환이 일어난다고 소개했다.
Continuation 객체는 코루틴의 일시 중지 지점이며, 코루틴이 다시 실행될 때 해당 지점에서부터 실행이 이어지도록 보장한다.

import kotlinx.coroutines.*
import java.time.LocalDateTime

fun main() {
    GlobalScope.launch { drawBackground() }
    GlobalScope.launch { drawBuilding() }
    GlobalScope.launch { drawPerson() }

    Thread.sleep(10000) // 메인함수의 종료를 방지하기 위해 현재 스레드 멈춤
}

suspend fun drawBackground() {
    logging("Start to draw background")
    delay(5000)
    logging("End draw background")
}

suspend fun drawBuilding() {
    logging("Start to draw building")
    delay(2000)
    logging("End draw building")
}

suspend fun drawPerson() {
    logging("Start to draw person")
    delay(3000)
    logging("End draw person")
}

fun logging(msg: String) {
    println("${LocalDateTime.now()} : $msg")
}

위 예제에서, 그림을 그리는데 얼마나 걸릴까?
총 10초일것 같지만, 사실 5초가 소요된다.

2023-03-01T14:37:19.714410 : Start to draw background
2023-03-01T14:37:19.714747 : Start to draw building
2023-03-01T14:37:19.714816 : Start to draw person
2023-03-01T14:37:21.738739 : End draw building
2023-03-01T14:37:22.730639 : End draw person
2023-03-01T14:37:24.734863 : End draw background

각 suspend fun 은 협력적으로 동작하며,
background, building, person을 번갈아서 그린다.

  1. background, building, person 코루틴 블록의 launch가 수행되면, Continuation 객체를 생성하고 스테이트 머신에 등록한다.
  2. building, person, background이 순차적으로 완료되면서, Continuation 객체를 통해 완료된 지점 (delay 이후)부터 수행한다.

* 이는 Coroutine State Machine 에 의해 관리되며, 자세한 내용은 나중에 다시 포스팅한다!

동시성 프로그래밍

동시성 프로그래밍과 비교해야할 개념으로 병렬성 프로그래밍이 있다.
간단하게, 2가지 일이 있으면
동시성 프로그래밍 : 손 하나로 겁나 빠르게 번갈아가면서 함
병렬성 프로그래밍 : 손 두개로 동시에 함

코루틴은 메소드 간, suspend() 와 resume() 으로 동작되는 동시성 프로그래밍이다.

동시성 프로그래밍과 병렬성 프로그래밍에 대한 차이는 링크를 참고해도 좋을듯 하다.
(그림을 쉽게 잘 그려주셨다.)

Reference
https://en.wikipedia.org/wiki/Coroutine
https://whyprogrammer.tistory.com/596
https://blog.yena.io/studynote/2020/04/26/Android-Kotlin-Coroutine.html
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://sungjk.github.io/2021/08/01/what-is-coroutine.html
https://www.charlezz.com/?p=44646

profile
A fast learner.

0개의 댓글