2022. 9. 15. 01:54ㆍ[Android APP] feat. Kotlin/Kotlin 공부
개요
Coroutine과 Thread를 알기 전에 이들은 어디에 사용되는 것일까?
먼저 비동기 처리를 알아야한다.
비동기(Asynchronous : 동시에 일어나지 않는)란?
특정 로직의 실행이 끝날때까지 기다려주지 않고 나머지 코드를 먼저 실행하는 것을 뜻한다.
쉽게 말하면 동시에 여러 작업을 할 수 있도록 도와주는 것이다.
Coroutine과 Thread는 이같은 비동기 작업에 사용한다.
안드로이드에서 네트워크의 값을 가져올 때 Main Thread가 아닌 별도의 Thread에서 동작하도록 구현해야한다.
본문
Thread가 뭐고 코루틴이 뭐야?
Thread
1. 각 태스크에 해당하는 스택 메모리를 할당받는다.
(각 Thread가 독립적인 Stack 메모리 영역을 가진다)
2. 여러 작업을 동시에 수행해야할 때 OS 는 어떤 쓰레드 작업을 먼저 수행할지, 어떤 쓰레드를 더 많이 수행해야 효율적인지에 대한 스케쥴링 (선점 스케쥴링, Preempting Scheduling) 을 한다.
3. 운영체제 커널에 의한 Context Switching 을 통해 동시성 보장
블로킹 (Blocking) : Thread1이 Thread 2의 결과를 기다려야한다면 Thread 1 은 블로킹되고 Thread 2 의 결과가 나올 때 까지 해당 자원을 쓰지 못한다.
Coroutine
1. Lightweight Thread 라고 부른다.
2. 작업 하나하나에 Thread 를 할당하는 것이 아닌 'Object' 를 할당해주고, 이 Object 를 자유롭게 스위칭함으로써 Context Switching 비용을 대폭 줄인다.
3. 코드를 통해 Switching 시점을 정한다.
Suspend (Non-Blocking) : Object 1 이 Object 2 의 결과가 나오기까지 기다려야 한다면, Object 1 은 Suspend 되지만, Object 1 을 수행하던 Thread 는 그대로 유효하기 때문에 Object 2 도 Object 1 과 동일한 Thread 에서 실행될 수 있다.
Coroutine 은 Thread 의 대안이 아니라, Thread 를 더 잘게 쪼개어 사용하기 위한 개념이다.
- 작업의 단위를 Object 로 축소하면서 하나의 Thread 가 다수의 코루틴을 다룰 수 있기 때문에, 작업 하나하나에 Thread 를 할당하며 메모리 낭비, Context Switching 비용 낭비를 할 필요가 없다.
코루틴의 종류
1) 코루틴 스코프 ( CoroutineScope)
- 글로벌 스코프(GlobalScope): 앱의 생명주기와 함께 동작하므로 생명주기를 따로 관리해 줄 필요가 없다.
- 앱이 시작할 때 부터 끝날 때 까지 긴 시간 실행되는 코루틴의 적합하다.(메인 스레드가 닫히면 같이 닫힌다.)
- 코루틴 스코프(CoroutineScope): 코루틴이 필요할 때만 사용하고 닫아주는 경우에 적합하다.
2) 코루틴 디스패쳐 ( Dispatcher )
디스패처는 코루틴을 적당한 스레드에 할당하고 코루틴이 정지하거나 다시 실행하는 것을 담당한다.
코루틴 디스패처의 종류에는 Default, IO, Main, Unconfined 등이 있다.
- Dispatchers.Default : 안드로이드 기본 스레드 풀을 사용한다. CPU를 많이 쓰는 데이터 정렬이나 복잡한 연산 같은 작업에 최적화 되어있다.
- Dispatchers.IO : 이미지 다운로드, 파일 입출력 등 네트워크, 디스크, DB작업에 최적화 되어있다.
- Dispatchers.Main : 안드로이드 기본 스레드에서 코루틴을 실행한다. UI와 상호작용에 최적화 되어있다.
- Dispatchers.Unconfined : 호출한 context 를 기본으로 사용하는데 중단하고 다시 실행될 때 context가 바뀌면 바뀐 context로 따라간다.
3) 코루틴 상태관리
- cancel : 코루틴의 동작을 멈추게 하는 method이다. 하나의 스포크 안에 여러개의 코루틴이 존재할 때 하위 코루틴까지 모두 멈춘다.
- join : 코루틴 내부에 여러 launch 블록이 있을 경우 모두 새로운 코루틴으로 분기되어 동시에 실행되기 때문에 순서를 정할 수 없다. 순서를 정해야할때 join method 를 이용해서 코루틴이 순차적으로 실행할 수 있도록 할 수 있다.
4) 코루틴 suspend 함수
suspend가 붙은 함수가 호출되면 호출한 코드를 잠시 멈추게 해서 스레드가 멈추지 않는 효율적인 스레드 활용을 할 수 있게 된다. 코루틴이 멈출 때 코틀린 런타임은 해당 코루틴이 실행되던 스레드에 다른 코루틴을 할당해서 실행시킨다. 그리고 멈춰있던 코루틴이 다시 실행될 때 사용 가능한 스레드에 할당해준다. 코루틴은 멈추면서 해당 루틴 상태를 저장하고 서브 루틴을 실행한 다음 저장한 부모루틴을 복원하는 방법으로 스레드에 영향을 주지 않는다.
5) 코루틴 빌더
- launch : 현재 스레드를 중단하지 않고 코루틴을 바로 시작한다. 결과를 호출한 쪽에 반환하지 않는다. 일반 함수에서 suspend 함수를 호출할 때와 코루틴의 결과가 필요 없을 때 사용한다.
- async : 현재 스레드 중단 없이 코루틴을 바로 시작한다. launch와 다른점은 호출 쪽에서 await() 을 통해 코루틴 결과를 기다릴 수 있다. 다수의 코루틴을 사용할 때 사용한다. suspend 함수 내부에서만 사용할 수 있다.
- withContext : 부모 코루틴에 의해 사용되던 context와 다른 context에서 코루틴을 실행 할 수 있다.
- coroutineScope : 다수의 코루틴을 suspend 함수가 시작하고 모든 코루틴이 완료될 때만 어떤 처리가 필요한 경우에 적합하다. 여러 코루틴 중에서 하나라도 실패하면 모든 코루틴이 취소된다.
- supervisorScope : coroutineScope와 비슷하지만 여러 코루틴 중에서 하나가 실패해도 다르 코루틴이 취소되지 않는 다는 점이 다르다.
- runBlocking : 코루틴을 시작하고 완료될 때 까지 현재 스레드를 중단시킨다.
5-1) 코루틴 suspend function
- withTimeout : 코루틴이 정해진 시간 안에 실행되지 않으면 예외를 발생시킨다.
- withTimeoutOrNull : 정해진 시간 안에 실행되지 않으면 null을 반환한다.
- awaitAll : 모든 작업의 성공을 기다리면서 작업중에 하나라도 실패하면 awaitAll 또한 실패한다.
- joinAll : 모든 작업이 끝날 때 까지 현재 작업을 일시 중단시킨다.
코루틴 사용법
app gradle에 아래 줄을 추가해준다.
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
코루틴의 Job(작업) 추가
private var job : Job?= null
job = GlobalScope.launch(Dispatchers.IO) {
//작업...
delay(1000)
}
코루틴 실행
job.join()
코루틴 종료
job.cancel()
Thread 사용법
Thread{
//작업
}.start()
'[Android APP] feat. Kotlin > Kotlin 공부' 카테고리의 다른 글
Android Kotlin : MultiPart를 이용해 서버로 파일 보내기 (2) | 2022.09.21 |
---|---|
Android Kotlin : MVVM, MVP, MVC 디자인 패턴이란 무엇일까? (0) | 2022.09.20 |
Android Koltin : 비밀번호, 이메일 등 정규식 (0) | 2022.09.12 |
Android Kotlin : 사용자 저장소 권한(Permission) 체크 (0) | 2022.09.12 |
Android Kotlin : 전화번호 및 주민등록번호 하이픈(-) 처리 (0) | 2022.09.08 |