코루틴

Shaun·2024년 5월 5일
1

Kotlin

목록 보기
9/10
post-thumbnail

루틴과 코루틴

  • runBlocking : 일반루틴 세계와 코루틴 세계를 연결한다. {} 괄호안에 있는 것들은 코루틴
  • launch : 반환값이 없는 코루틴을 만든다. 만들어 놓은 코루틴을 바로 실행시키지 않는다.
  • yield : 지금 코투린을 중단하고, 다른 코루틴이 실행되도록 한다 ( 스레드를 양보한다)
  • suspend fun : 다른 suspen fun을 호출할 수 있다.

  • 코루틴은 루틴이 중단되었다가 해당 메모리에 접근이 가능하다.

  • 어떤 스레드에서 동작하는지 확인

  • VM option까지 추가하면 어떤 스레드의 몇번째 코루틴이 사용된는지 알 수 있다.

스레드와 코루틴

  • 프로세스가 스레드보다 큰 개념이듯이, 스레드가 코루틴 보다 큰 개념이다

  • 코루틴은 코루틴이 직접 코드를 실행시키는게 아니라 가지고 있는 코드를 스레드에 넘겨서 실행한다

  • 코루틴은 스레드에 종속적이지 않아 중단 되었다가 재개될 때 다른 스레드에 배정될 수 있다.

스레드: heap메모리를 공유하고, Stack만 교체되므로 프로세스보다 비용이 적다

코루틴: 동일 스레드에서 실행되면, 같은 heap메모리, stack을 공유하므로 context switching 비용이 낮다.

-> 하나의 스레드에서 동시성을 확보할 수 있다.

runBlocking

  • runBlocking 안에 있는 코루틴이 완료될때까지 스레드를 블락킹 시킨다. END는 runblocking이 끝나야 실행된다.

launch

  • job1 이 delay하는 동안 job2가 실행되서 최종 1.1초 정도 걸림
  • 반환값이 없는 코루틴을 만든다. 여기서 반환된 값은 반환값이 아니라 이 코루틴을 컨트룰할 수 있는 객체임.

  • start() : 시작

  • cancel() : 취소

  • join() : 해당 코루틴이 완료될 때까지 대기

  • async : 주어진 함수의 실행결과를 반환할 수 있다
  • await() : asynce의 결과를 가져오는함수, asynce의 결과를 바로 가져올 수 없다.
  • async : 여러 API를 동시에 호출해서 실행시간을 단축 시킬 수 있다.

  • async(Lazy옵션) : 계산결과를 기다리고 넘어감.
    -> async라 동시에 시작하는게 아니라 job1기다리고 그 값이나오면 job2실행

  • start() 함수를 한번 호출해주면 다시 괜찮아진다.

코루틴 취소

  • cancel() 로 취소 실키수 있지만 취소 당하는 코루틴도 협조 해줘야함

취소 협조 조건

  • yield 나 delay 처럼 suspend 함수를 사용해야함

  • suspend 함수를 사용하지 않는경우 무한루프에 걸릴수 있다.

  • delay() / yield() 와 같은 kotlinx.coroutines 패키지의 suspend 함수를 사용해야 한다.

  • 코루틴 스스로 본인의 상태를 확인해 취소 요청을 받았으면, CancellationException을 던져야함

  • delay(), /yield() 는 이미 CancellationException을 던져 그걸로 취소시키는데 try-catch로 잡아버리면 취소가 안됌

  • isActive를 통해 현재 코루틴이 활성화 되어있는지, 취소 신호를 받았는지 확인 가능

  • launch(Dispatchers.Default) 를 사용하면 lauch안에 있는 코드는 다른 스레드에게 실행시킨다.

코루틴 예외처리

  • CoroutineScope(DisPatchers.Default) = 다른 스레드에서 새로운 코루틴 영역 생성 == root 코루틴 생성

async VS launch

  • lauch 는 예외발생시 예외를 읽고 코루틴을 멈추지만 async는 예외를 뱉지 않음, await로 찍어야 예외 터짐

  • root 코루틴이 아닌, 자식 코루틴에서 예외가 터질경우 부모 코루틴까지 전파 시키기 때문에 async를 사용해도 예외 발생함

  • 자식 코루틴에서 예외 전파 안하려면 async(SupervisorJob())사용

코루틴 예외 다루기

  • try catch
  • exception hanlder

  • lauch 안에 있는 예외를 try-catch로 잡으면 코루틴이 종료되지 않고 진행된다.

  • 에러를 로깅, 메세지 전파, 공통된 로직을 사용하고 싶으면 CoroutineExceptionHandler 사용 -> 이 핸들러는 launch()에만 적용 가능하며 부모 코루틴이 있으면 동작하지 않는다.

-> 큰 차이점은 try-catch를 사용시 예외가 발생 하지 않은것처럼 간주된다는, Handler는 사용하면 로깅 찍히니까

코틀린 예외 VS 취소(CancellationException)

  • 발생한 예외가 CancellationException인 경우 취소로 간주하고 부모 코루틴에게 전파 x

  • 다른 예외는 실패로 간주하고 부모 코루틴에게 전파

-> 둘다 내부적으로는 취소됨 으로 간주, 차이점은 부모에게 전파하느냐 안하느냐

부모코루틴 자식코루틴 취소 절차

  • 코루틴이 실행된 뒤에 Completing이 존재하는 이유는 부모 코루틴이 다른 자식 코루틴 결과값을 기다리기 때문.(다른 한쪽의 자식 코루틴이 실패할 수 도 있으니까)

  • 첫번째 사진에서는 1번자식 코루틴이 일을 먼저 끝내고 2번자식에서 예외가 발생 -> 부모 전파 == 1번은 성공

  • 두번째 사진에서는 2번째 자식에서 먼저 실패 -> 부모 예외 전파 -> 자식루틴에게 취소명령내림 == 둘다 실패

-> 이렇게 한몸처럼 움직이는것을 Structured Concurrency라고 한다

-> 자식 코루틴에서 예외가 발생하지 않더라도 부모 코루틴이 취소되면 자식 코루틴들도 취소 된다!!

-> CaccellationException은 정상적인 취소로 간주하기 때문에 부모 코루틴에게 전파되지 않고, 부모 코루틴의 다른 자식 코루틴을 취소시키지 않는다.

CoroutineScope와 CoroutineContext

  • launch, async는 CoroutineScope의 확장 함수 이다. 즉 runBlocking이 CoroutineScope를 제공해 준다.

  • 우리가 CoroutineScope를 만들면 runBlocking은 필요하지 않다.

CoroutineScope

  • coroutineContext라는 데이터를 보관하는 것

  • CoroutineScope를 취소함으로 여러 코루틴을 한번에 종료 시킬 수 있다.

  • 코루틴의 Structured Concurrency 기반

CoroutineContext

  • 코루틴과 관련된 데이터, 코루틴 이름, 코루틴 그 자체 ,CoroutineExceptionHanlder, CoroutineDispatcher 을 가지고 있다.

  • Map+Set을 합쳐놓은 상태,( key-value이면서 같은 key의 데이터는 유일함)

  • key-value를 element라고 하며 서로 합칠 수 도 있다.

  • CoroutineContext를 통해 해당 코루틴의 CoroutineContext에 접근 가능

CoroutineDispatcher

  • 코루틴이 어떤 스레드에 배정될지를 관리하는 역활

종류

  • Dispatcher.Default = 가장 기본적인 디스패쳐
  • Dispatcher.IO = IO작업에 최적화
  • Dispatcher.Main = UI컴포넌트를 조작하기 위한 디스패처, 특정 의존성을 갖고 있어야 정상적으로 활용할 수 있다.

ExecutorService를 디스패처로

  • asCoroutineDispatcher 확장함수를 통해 스레드풀을 코루틴 디스패처로 바꾼다

Suspending Function

  • 코루틴이 중지 되엇다가 재개 될 수 있는 지점

  • 첫번쨰 사진은 async의 반환타입인 Deferred에 의존적이다. 하지만 이럴때 suspendFunction을 사용하면 여러 비동기 라이브러리를 사용할 수 있도록 도와준다

- coroutineScope는 async나 launch 처럼 start를 기다리지 않고 블록이 바로 실행 된다.

withContext

  • coroutineScope 와 매우 흡사하며 단지 context에 변화를 주는 기능만 추가됨

withTimeout / withTimeoutOrNull

  • coroutineScope 와 기본적으로 유사함. 주어진 시간 안에 새로 생간 코루틴이 완료 되어야 한다.
profile
호주쉐프에서 개발자까지..

0개의 댓글