엄코딩의 개발 일지

사내 업무량을 어느 정도 마치고, 오랜만에 다시 코루틴 학습을 시작했습니다.

 

역시 복습하니 다시 모르는게 보였습니다. 그래서 정리의 필요성을 느끼고 포스팅을 시작했습니다.

 

코루틴에 대해서 처음부터 학습하실 분들은 저의 이전 포스팅들이나 구글 Document를 보시는 것을 추천드립니다.

 

//CoroutineScope는 runBlocking 내부에서만 사용 가능
    //runBlocking, coroutineScope 차이점
    //coroutineScope에서는 자식 스레드가 완료될 때 까지 현재 스레드를 block 하지 않는다.
    //runBlocking에서는 자식 스레드가 완료될 때 까지 현재 스레드를 block 한다.
    fun main() = runBlocking { // this: CoroutineScope
        //자식 스레드가 완료될 때 까지 현재 스레들 block 한다.

        //자식 스레드가 완료될 때 까지 현재 스레드를 block한다고 하는데
        //왜 아래 coroutineScope에 "Task from coroutine scope"가 먼저 실행 되는건지 궁금합니다.
        launch {
            delay(200L)
            Log.e("main","Task from runBlocking")
        }

        coroutineScope { // Creates a coroutine scope
            //자식 스레드
            launch {
                delay(500L)
                Log.e("main","Task from nested launch")
            }
            //현재 스레드
            delay(100L)
            Log.e("main","Task from coroutine scope")
        }
        Log.e("main","Coroutine scope is over")
    }

 

정리해보니 위와 같았습니다.

 

주석을 열심히 달아보고, 혼자 질문도 해봅니다 ㅎㅎ( 사실 한참 고민하다가 오픈채팅방에 자문을 구했습니다. )

 



질문하려고 주석을 정리하다보니 저의 질문에 의심을 품게 되었습니다. ( 사실 제가 틀에 박힌 생각을 하고 있지는 않았나 싶어서... )

 

항상 느끼는 거지만, 질문을 하려고 정리하다보면 문득 정답이 스쳐간다는...

 

답변해주신 태환님께 정말 감사했습니다! ( 문제가 될 시 삭제하겠습니다.)

 

runBlocking은 자식 스레드가 완료될 때 까지 현재 스레드를 block하는 것이고, coroutineScope는 자식 스레드가 완료될 때 까지 현재 스레드를 block 하지 않는다.

 

"launch는 그냥 스레드를 돌려두는 것이고, coroutineScope 자체가 async/await 할때까지 기다린다"

 

위 문장까지 들었을 때는 사실 아직도 헷갈리고 있었는데,

 

"coroutineScope 자체가 async/await이고, coroutineScope 안에서 다시 launch 하면 그냥 또 돌아간다" 라는 말을 듣고 이해할 수 있었습니다.

 

그래서 저에게 좀 더 이해하기 쉽도록 예제 코드를 작성해봤습니다.

 

// Job을 등록할 수 있도록 초기화
    // CoroutineScope의 동작을 제어할 객체
    // 안드로이드 상에서는 Lifecycle을 활용할 수 있도록 도와준다.
    lateinit var job : Job


    // coroutine의 스레드를 어떠한 형태로 사용할지 지정할 수 있다.
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job



    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        job = Job()

        runBlocking {
            delay(1000L)
            Log.e("coroutineScope","STEP 1")
        }

        Log.e("coroutineScope","STEP 2")

        CoroutineScope(coroutineContext).launch{
            delay(1000L)
            Log.e("coroutineScope","STEP 4")
        }


        Log.e("coroutineScope","STEP 3")

    }

    // 작업 중이던 모든 job, children을 종료 처리
    override fun onDestroy() {
        super.onDestroy()
        job.cancel()
    }

 

실행순서는 STEP1 -> STEP2 -> STEP3 -> STEP4 

 

이제 생각대로 흘러가는 것 같습니다.

 

참고로 위에서 쓰인 Dispatchers는 코루틴을 실행할 때 어떤 스레드를 사용할 것인지 결정하기 위해 사용됩니다.

 

Dispachers.Main은 안드로이드에서는 Main 스레드 즉, UI 스레드를 위해서만 사용됩니다. 또한 suspend functions, UI 프레임워크 연산, 최근에는 LiveData update를 위해 사용됩니다.

 

이외에도 Dispatchers.IO, Dispatchers.Defaule가 존재합니다. 자세한 내용은 링크를 통해 확인해보시면 좋을 것 같습니다.

 

 

참고자료 

 

https://thdev.tech/coroutines/2019/04/08/Init-Coroutines-Job/

 

Kotlin Coroutines의 Job 동작을 알아보자

개인 광고 영역 Kotlin Coroutines을 컨트롤하기 위한 Job을 제공해준다. 이 Job은 N 개의 coroutines의 동작을 제어할 수도 있으며, 하나의 coroutines 동작을 제어할 수도 있다. 먼저 Job이 어떤 것인지 알아보고, exception 발생 케이스를 함께 알아보겠다. Job Coroutines의 Job은 결국 coroutines의 상태를 가지고 있는데, 아래와 같은 6가지 상태를 포함하고 있으며, active/complet

thdev.tech

 

https://developer.android.com/kotlin/coroutines

 

Improve app performance with Kotlin coroutines  |  Android Developers

A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously. Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages. On Android, coroutines help to

developer.android.com