[kotlin] 코루틴이란?, runBlocking?, suspendCancellableCoroutine
2021. 6. 3. 14:39ㆍ모바일/Android_Kotlin
코루틴?
- 비동기 라이브러리
- 경량 스레드
- OS에 의존적인 스레드와는 달리 스레드간 컨텍스트 전환 비용이 발생하지 않으며, 개발자가 직접 중지 지점을 선택할 수 있다.
기본적인 사용법
val scope = CoroutineScope(Dispatchers.Default)
scope.launch{
//do
}
scope.launch(Disaptchers.IO){
//some I/O
}
- 위 코드처럼 어느 스케줄러에서 비동기 로직이 실행될지 결정할 수 있다.
- 이런식으로 디스패치를 사용해서 어느 스레드풀에서 어느 로직이 실행될지를 결정할 수 있고 로직들의 규모를 세세하게 나눌 수 있다.
서스펜딩(suspending)
- 코루틴이 실행 중인 스레드를 블록킹하지 않으면서 실행 중인 코루틴을 잠시 중단시킬 수 있는 중단 지점 함수
- 서스펜딩 함수를 호출하는 시점에 현재 실행중인 코루틴은 잠시 중단되고, 그 때 남게 되는 스레드는 다른 코루틴에 할당될 수 있음을 의미한다
- 서스펜딩 함수의 로직이 끝났을 때에 중단되었던 코루틴은 다시 실행 준비가 됩니다.
기본적인 사용법
suspend fun asyncFunction(){
}
네트워크 호출 사용법
suspend fun netWorkCall(): String{
delay(1000)
return "data from network"
}
suspend fun uiFunction(){
val data = netWorkCall()
println(data)
}
fun main(){
// println(alphabetWith())
// println(alphabetApply())
//callFunction()
val scope = CoroutineScope(Dispatchers.Default)
scope.launch {
println("coroutine. ${Thread.currentThread().name}")
uiFunction()
}
Thread.sleep(500)
scope.launch {
println("another coroutine. ${Thread.currentThread().name}")
}
println("main is done. ${Thread.currentThread().name}")
Thread.sleep(2000)
}
사용법2
fun main(){
start()
다른
함수
들
}
fun start(){
startCoroutine{
함수1()
함수2()
함수3()
}
}
suspend 함수1(){
delay(1000)
}
suspend 함수2(){
delay(1000)
}
suspend 함수3(){
}
설명
- main 함수를 실행하면 coroutine이 시작된다.
- 함수1() 에서 suspend함수를 만나고 start함수를 탈출한다
- 메인쓰레드가 start함수를 탈출하고 다른 코드들 (다른함수들)을 실행한다.
- 함수1()은 다른 쓰레드에서 계속 실행중이다.
- 메인쓰레드가 다른 코드들을 실행하다가 함수1()이 끝나면 탈출했던 코루틴으로 돌아온다
- 함수1() 아래 함수인 함수2()부터 resume된다.
withContext와 coroutineScope의 비교
두 함수 모두 suspend fun으로서 코루틴 내부에서 블록을 중단시키기 때문에 유사해 보인다.
그러나, coroutineScope는 withContext의 한 유형으로 볼 수 있다.
즉, coroutineScope는 withContext(this.coroutineContext) 와 본질적으로 같은 의미를 지닌다.
coroutineScope는 Dispatcher를 설정할 수 없다 (무조건 현재 호출한 context를 사용하기 때문이다)
- coroutineScope는 에러처리 등의 목적으로 특정 코드를 하나의 블럭으로 묶고 싶을 때 사용
- withContext는 해당 코드블럭을 특정 Context에서 실행하고 싶을 때 사용하는 용도 (네트워크 작업을 위한 IO Dispatcher 등)
하지만 coroutineScope 내에서 Exception을 Throw하면 전체 부모 루틴이 중지되는데 아래의 문구를 살펴보면 에러 핸들링 목적으로 사용한다는 말이 잘 이해가 되지 않는다.
사용법 3 (with runBlocking)
fun main() {
println("run")
CoroutineScope(Dispatchers.Default).launch {
(0..10).forEach{
val sum = (it..10).toMutableList().sum()
println(sum)
}
}
println("wait")
runBlocking {
delay(2000L)
}
println("Test end")
}
//출력
run
wait
55
55
54
52
49
45
40
34
27
19
10
//여기서 main함수가 블록킹 되면서 2초 후에 아래 문자 출력
Test end
언제 사용하는가?
- 명확한 IO를 보장하고, 데이터으 ㅣ동기화가 필요한 경우와, UnitTest작성 시에 사용하는게 좋을것이다
runBlocking과 사용
fun main() = runBlocking {
println("run")
CoroutineScope(Dispatchers.Default).launch {
println("왜안됨")
}
println("The End")
}
//출력
run
The End
왜안됨
- 위 코드에서 runBlocking{} 빌더로 생성된 코루틴 블록은 lanch빌더를 이용해 생성한 코루틴이 종료될때까지 대기한 후 종료된다.
fun main() {
println("run")
CoroutineScope(Dispatchers.Default).launch {
println("왜안됨")
}
println("The End")
}
//출력
run
The End
- 위 코드처럼 실행되는 코루틴은 호출(실행) 쓰레드를 블록하지 않기 때문에 메인함수가 종료되면서 메인 함수를 실행한 메인 스레드 역시 종료되어 프로그램이 끝난다.
fun main() {
println("run")
CoroutineScope(Dispatchers.Default).launch {
println("왜안됨")
}
println("The End")
runBlocking {
delay(2000L)
}
}
runBlocking 없이 사용
suspend fun main() {
println("run")
hello()
println("The End")
}
suspend fun hello(){
suspendCancellableCoroutine <hi?>{hi->
println("왜안됨")
val hello2 = hi()
hi.resume(hello2)
}
}
//출력
run
왜안됨
The End
'모바일 > Android_Kotlin' 카테고리의 다른 글
RecyclerView Item 드래그 앤 드랍(Drag and Drop) 순서 변경 (0) | 2021.06.09 |
---|---|
Generic 클래스와 함수 정리 (0) | 2021.06.04 |
LiveData - Transformations.map, switchMap (0) | 2021.06.03 |
AndroidManifest.xml receiver tag is incompatible with attribute description (attr) reference. (0) | 2021.03.08 |
DataBinding – Two-way(양방향) Databinding with Custom View (0) | 2021.03.04 |