async 코루틴 빌더 생성
동시성 처리를 위한 async 코루틴
- launch 와 다른점은
Deffered<T>
를 통해 결과 값을 반환
- 지원된 결과 값을 받기 위해
await()
를 사용
private fun worksInParalled() {
val one = GlobalScope.async {
dowork1()
}
val two = GlobalScope.async {
dowork2()
}
GlobalScope.launch {
val combined = one.await() + "_" + two.await()
println("Kotlin Combined : $combined")
}
}
Coroutine Context
- 코루틴을 실행하기 위한 다양한 설정값을 가진 관리 정보
- 코루틴 이름, 디스패치, 작업 상세사항, 예외 핸들러 등
- 디스패처는 코루틴 문맥을 보고 어떤 스레드에서 실행되고 있는지 식별이 가능해진다.
- 코루틴 문맥은 + 연산을 통해 조합될 수 있다
val someCoroutineContext = someJob + Dispatchers.IO + someCoroutineName + someExceptionHandler
CoroutineName
val someCoroutineName = CoroutineName("someCoroutineName")
Job
- 작업 객체를 지정할 수 있으며 취소 가능 여부에 따라
SupervisorJob()
사용
val parentJob = SupervisorJob()
val someJob = Job(parentJob)
CoroutineDispatcher
- Dispatchers.Default, ... IO, 등을 지정할 수 있으며 필요에 따라 스레드풀 생성 가능
val mypool = Excutors.newFixedThreadPool(2).asCoroutineDispatcher()
코루틴 문맥
CoroutineExceptionHandler
- 코루틴 문맥을 위한 예외처리를 담당하며 코루틴에서 예외가 던져지면 처리한다
- 예외가 발생한 코루틴은 상위 코루틴에 전달되어 처리될 수 있다
- 스코프를 가지는 경우 예외 에러를 잡아서 처리 할 수 있다
- 만일 예외처리가 자식에게만 있곡 부모에 없는 경우 부모에도 예외가 전달되므로 주의
- 예외가 다중으로 발생하면 최초 하나만 처리하고 나머지는 무시됨
val someExceptionHandler = CoroutineExceptionHandler { coroutineContext, throwalbe ->
val coroutineName = coroutineContext[coroutineName]?.name ?: "default coroutine name"
println("Error in $coroutineName : ${throwable.localizedMessage}")
}
코루틴 스코프
GlobalScope
val scope = GlobalScope
scope.launch { ... }
scope.launch { ... }
or
GlobalScope.launch { ... }
val job1 = GlobalScope.launch { ... }
val job2 = GlobalScope.async { ... }
- 독립형 코루틴을 구성, 생명주기는 프로그램 전체에 해당하는 범위를 가지며 main의 생명 주기가 끝나면 같이 종료됨
Dispatchers.Unconfined
와 함께 작업이 서로 무관한 전역 범위 실행
- 보통 GlobalScope 상에서는 launch나 async 사용이 권장되지 않음
CoroutineScope
val scope2 = CoroutineScope(Dispatchers.Default)
val routine1 = scope1.launch { ... }
val routine2 = scope2.async { ... }
or
CoroutineScope(Dispatchers.Main).launch { ... }
launch(Dispatchers.Default) { ... }
async(Dispatchers.Default) { ... }
- 특정 목적의 디스패처를 지정한 범위를 블록으로 구성할 수 있다
- 모든 코루틴 빌더는
CoroutineScope
의 인스턴스를 갖는다
- launch {..} 와 같이 인자가 없는 경우에는 coroutineScope에서 상위의 문맥이 상속되어 결정
- launch(Dispatchers.옵션인자) {...} 와같이 디스패처의 스캐줄러를 지정 가능
Dispatchers.default
는 globalscope
에서 실행되는 문맥과 동일하게 사용
스레드 풀
스레드 풀 사용
- 보통 commonPool이 지정되어 코루틴이 사용할 스레드의 공동 풀을 사용
- 이미 초기화되어 있는 스레드 중 하나 혹은 그 이상이 선택되며 초기화 하기 때문에
fun main() = runBlocking<Unit> {
val request = launch {
GlobalScope.launch {
println("job1 : before suspend function")
delay(1000)
println("job1: after suspend function")
}
launch {
delay(100)
println("job2: before suspend function")
delay(1000)
println("job2: after suspend function")
}
}
delay(500)
request.cancel()
delay(1000)
}
빌더의 특정 속성 지정
시작 시점에 대한 속성 - launch의 원형
public fun launch(
context: CoroutineContext,
start: CoroutineStart,
parent: Job?
onCompletion: CompletionHandler?,
block: suspend CoroutineScope.() -> Unit):Job {
...
)
CoroutineStart
DEFAULT
: 즉시 시작 (해당 문맥에 따라 즉시 스케줄링됨)
LAZY
: 코루틴을 느리게 시작 (처음에는 중단된 상태이며 start()나 await() 등으로 시작)
ATOMIC
: 원자적으로 즉시 시작 (DEFAULT와 비슷하나 코루틴을 실행전에는 취소 됨)
UNDISPATCHED
: 현재 스레드에서 즉시 시작 (첫 지연함수까지 이후 재개시 디스 패치 됨)
start(), await()
- launch나 async는 즉시 실행되지만 start 옵션에 따라 실행 시점을 늦출 수 있다
val job = async(start = CoroutineStart.LAZY) { dowork1() }
..
job.start()
Reference