Coroutine 과 놀아보기 #1 |
-
android studio 에서 coroutine 관련된 것들을 인식 못한다.
android 3.2.1 버전으로 업그레이드 하니 해결되었다.
해당 버전 이상으로 환경 세팅을 하고 시작하자!
-
이 글은 내가 coroutine 을 학습한 후에 약간 까리한 부분들을,
테스트 코드를 짜서 실험한 결과를 공유하는 글이다.
runBlocking?
새로운 coroutine 을 수행하며, 작업이 끝날 때까지 현재 thread 를 block 시킨다. (interrupt 가능하다.)
-
다음과 같은 테스트를 해보았다.
btn.setOnClickListener{ runBlocking{ startLogPrinting() // mainHandler 에서 50ms 마다 “logPrinting” 을 찍음 logCurrentThread() log(“before delay”) delay(2000L) log(“after delay”) } }
내가 예상한 결과는...
1. runBlocking 은 main thread 에서 불렸을 것이다.
2. delay 가 불렸을 때 main thread 가 block 되는 것이 아니라 “before delay” 를 찍기 전에 50ms 주기로 “log Printing” 들이 찍힐 것이라 생각
실제 결과는...
main
before delay
after delay
logPrinting
logPrinting
logPrinting
runBlocking 을 실행하는 순간, runBlocking coroutine 이 끝날때까지 Thread 를 계속 점유한다.
이 경우에는 MainThread 에서 runBlocking 을 수행했기 떄문에 Main 을 계속 점유하기 때문에, main handler 가 컨트롤을 가져가지 못한다.
이렇게 보면 결과가 이해가 된다.
-
여기서 한가지 궁금증이 생길 수 있다.
runBlocking(Dispatchers.Default){ } 로 로직을 수행시키면 결과가 달라질까?
답은, 결과는 같다!!
runBlocking 은 다시 말하지만 호출하는 thread 를 점유하고, runBlocking 의 coroutine 수행이 끝날때까지 wait 하는 로직이다.
기본 dispatcher?
-
main thread 에서 coroutineContext 지정 없이 launch 를 수행하면(runBlocking 안에서 launch) mainThread 에서 수행되고,
mainThread 에서 GlobalScope.launch 를 coroutineContext 없이 전달하면, DefaultDispathcer-worker-1 에서 수행된다.
runBlocking 안에서 MainThread 에 대한 launch?
-
btn.setOnClickListener{ runBlocking{ startLogPrinting() // mainHandler 에서 50ms 마다 “logPrinting” 을 찍음 launch{ logCurrentThread() log(“before delay”) delay(2000L) log(“after delay”) } } }
launch 가 없는것과 동일한 결과를 낸다.
Multiple launch in runBlocking?
-
btn.setOnClickListener{ runBlocking{ launch{ delay(10000L) log("10sec delay ends!") } launch{ logCurrentThread() log(“before delay”) delay(2000L) log(“after delay”) } log(“How about this?”) } }
앞서 single launch 를 돌리며 생각했다.
runBlocking 이 Main Thread 를 점유하는데 launch 를 탄 것은 동일 thread 이기 때문에 바로 실행한것인가?
아니면 coroutine scope 내에서의 main thread 점유는 우리가 알고 있는 coroutine 동작대로 동작할까?
이 실험의 결과는..
How about this?
main
before delay
after delay
10sec delay end
logPrinting
logPrinting
...
즉, runBlocking 을 호출하였더라도 coroutine context 내에서의 thread share? 는 동작한다.
-
자 그럼 이 결과는 어떻게 될까 예상해보라.
runBlocking{ startLogPrinting() // mainHandler 에서 50ms 마다 “logPrinting” 을 찍음 launch{ logCurrentThread() log(“before delay 1”) delay(2000L) log(“after delay 1”) } launch{ logCurrentThread() log(“before delay 2”) delay(1000L) log(“after delay 2”) } log("Yap!”) }
결과는...
-
이번 놀아보기로 얻은 성과는...
1. runBlocking 이라는 것이 non suspend 환경과 suspend 환경의 bridge 가 된다는 것!
2. launch 를 main thread 에서 수행하더라도 block 단위로 queuing 되어 들어간다고 보면 된다는 것 (즉각 실행이 아님) - 사실 기본 중 기본!
3. coroutine 간에는 delay 가 non-blocking 으로 작동. (thread-share 됨)
괜히 handler 가 들어가면서 복잡해졌는데... 그렇지만 꼭 알아야 하는데...
1. coroutine 간에는 delay 가 non-blocking 으로 작동하지만, coroutine 이 아닌 것에는 blocking 처럼 작동한다..
2. 따라서 onClick runBlocking 을 수행하고 그 안에서 delay 를 주면… onClick 을 여러번 수행하면 ANR 에 걸릴 수 있다…. coroutine 바깥쪽 입장에서는 delay 가 Thread.sleep 과 비슷한 효과를 발휘한다.
마지막으로...
coroutine 의 실제 동작은 생각한 것과 참 많이 다를 수 있다.
직접 테스트해보고 쪼물쪼물 만져보며 익혀야 할 것 같다.
'프로그래밍 놀이터 > Kotlin, Coroutine' 카테고리의 다른 글
[coroutine] Coroutine Basics ( 코루틴 기초 ) (4) | 2020.03.07 |
---|---|
Coroutine 과 놀아보기 #2 (2) | 2019.05.23 |
Coroutine first launch slow.. (0) | 2019.04.26 |
[coroutine] java.lang.IllegalStateException: Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher, e.g. 'kotlinx-coroutines-android' (0) | 2019.03.06 |
[coroutine] exception 을 이해해보자 #2 ( in global scope ) (0) | 2019.03.06 |
댓글