[안드로이드] Coroutine

이상욱·2022년 12월 23일
0

안드로이드

목록 보기
10/17
post-thumbnail

✅ Coroutine

AsyncTask

  • 손쉬운 비동기 프로그래밍
  • 메모리 누수 등 여러 문제 발생
  • API30 부터는 Deprecated
  • 대체제로 코루틴 권장

Routine

  • 메인루틴
  • 서브루틴
  • 코루틴

코루틴과 스레드의 차이점

1. 메모리 구조 차이

핸드폰 안의 프로그램을 실행시키면 메모리에 로드가 됩니다. 프로그램이 로드되면 로드 된 인스턴스를 프로세스라고 합니다. 실행된 프로세스는 여러 개의 공유된 실행의 흐름을 갖게 되는데 실행 흐름 하나 하나를 쓰레드라고 합니다. 프로세스는 자기가 사용하기 위해서 메모리 영역을 할당받는데 Heap메모리라고 합니다. 프로세스 내의 쓰레드마다도 메모리가 할당 됨 이 메모리를 Stack메모리라고 합니다. 코루틴은 쓰레드처럼 메모리를 할당 받지 않고 프로세스의 Heap메모리를 공유하고 있습니다.

2. 수행방식의 차이

코루틴은 비선점형 멀티태스킹, 쓰레드는 선점형 멀티태스킹
쓰레드는 실제로 멀티 코어를 사용해서 동일한 시간에 여러 작업을 할 수 있어 병행성이 있습니다.
반면, 코루틴은 동일한 시간에 같이 수행되지 않습니다. 코루틴이 전환되면서 수행되는 속도가 빠르기 때문에 동시에 수행되는 것 처럼 보입니다.
코루틴은 동시성은 있지만 병행성은 없습니다.

  1. 코루틴의 장점
    만약 3개의 작업을 쓰레드에서 작업한다면 Stack영역을 모두 할당해야하지만 코루틴은 할당할 필요가 없어 사용되는 메모리가 줄어들게 됩니다.
    그리고 쓰레드끼리 다른 메모리 영역에 있으므로 순서를 조정할 때 Context Switching이 일어나지만 코루틴은 Heap메모리를 공유하고 있기 때문에 Context Switching이 필요가 없어 오버헤드가 줄어들게 됩니다.

코루틴 구조

  • Coroutine Scope

  • Coroutine Context

  • Coroutine Builder

1. Coroutine Scope

코루틴이 동작하는 범위를 규정

  • CoroutineScope
public interface CoroutineScope{
	public val coroutineContext : CoroutineContext
}

스코프가 지정이 되면 특정한 CoroutineContext에서 Dispatchers를 설정해서 스코프의 영역을 제한할 수 있습니다.

  • GlobalScope
    Coroutine Scope의 한 종류이고 싱글톤으로 앱 최상위 레벨에서 코루틴을 수행하고 하는 특징이 있습니다. GlobalScope는 사용을 권장하지 않습니다.

2. Coroutine Context

  • Dispatchers
    Dispatchers는 코루틴이 실행되는 쓰레드를 선택합니다.

    Default : CPU 연산을 많이 사용하는 작업
     IO : 파일 I/O 또는 네트워크 I/O 
     Main : UI와 관련된 변경을 해야하는 경우
     Unconfined : 일반적인 용도에서 사용하지 않음
  • Job & Deferred
    코루틴 작업을 Job이나 Deferred 로 만들어서 다루게 됩니다.
    Deferred는 결과값을 반환하는 차이점이 있습니다.

    val job = scope.launch{
    	//New Coroutine
    }
  • Job State

  • Job Methods
    - cancel : 작업 중인 코루틴을 Cancelling상태로 만들 수 있다.
    - join :
    - start : 새로 만든 객체를 시작

3. Coroutine Builder

  • launch
    Job 객체 반환

  • async
    Deferred 객체 반환

  • runBlocking
    launch나 async는 Main쓰레드랑 관계없는 쓰레드이므로 방해하지 않습니다
    runBlocking을 사용하면 Main쓰레드를 Block을 한 후에 runBlocking안의 작업을 수행하게 됩니다. 실제로는 코루틴이 아니기 때문에 코루틴을 위해서는 사용을 하지 않는 것이 좋습니다.

  • withContext
    Dispatcher를 전환시키는 기능을 가지고 있습니다.
    Dispatchers switch
    Main쓰레드 내에서 작업을 하다가 IO작업이 필요한 경우 .withContext를 통해서 필요한 작업만 한 후 다시 main쓰레드를 수행할 수 있습니다.
    안드로이드 OS에서 스위칭을 관리하므로 오버헤드가 줄어드니다.

코루틴 지연

  • delay : 코루틴이 지정한 시간만큼 수를 세면서 대기합니다.(쓰레드 sleep의 개념과 다름)
  • join : launch로 실행한 코루틴은 join으로 job이 실행이 끝날 때 까지 대기시킬 수 있습니다.
  • await : async로 실행한 코루틴은 await로 Deferred 실행이 끝날때 까지 대기하고 끝나면 Deferred로 반환하게 됩니다.

코루틴 취소

  • cancel
  • cancelAndJoin
  • withTimeout
  • withTimeoutOrNull

예외 처리

  • CoroutineExceptionHandler를 이용하여 코루틴 내부의 기본 catch~block으로 사용할 수 있습니다.
  • launch, actor : exception 발생 시 바로 예외 발생
  • async, produce : 중간에 exception이 발생해도 await를 만나야 발생
  • job.cancel()를 제외한 다른 exception이 발생하면 부모의 코루틴까지 모두 취소시킵니다. 이는 structured concurrency를 유지하기 위함으로 CoroutineExceptionHandler를 설정해도 막을 수 없습니다.
  • 여러 개의 Exception이 발생하면 가장 먼저 발생한 exception이 handler로 전달되며 나머지는 무시됩니다.

레퍼런스
https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/
냉동코더의 알기 쉬운 Modern Android Developer 입문

profile
항상 배우고 성장하는 안드로이드 개발자

0개의 댓글