Android 공부/Coroutine

코루틴 기초 정리 _ part 01

Machine_웅 2022. 7. 14. 00:24
728x90
반응형

 

 

코루틴 컨텍스트

CoroutineContext 에는 Main, IO, Default의 세 가지가 있다.

  • Main은 말 그대로 메인 쓰레드에 대한 Context이며 UI 갱신이나 Toast 등의 View 작업에 사용된다.
  • IO는 네트워킹이나 내부 DB 접근 등 백그라운드에서 필요한 작업을 수행할 때 사용된다.
  • Default는 크기가 큰 리스트를 다루거나 필터링을 수행하는 등 무거운 연산이 필요한 작업에 사용된다.

 

 

 


코루틴 빌더

launch

- 새로운 코루틴을 만들어주는 빌더 역할을 한다. 

- 이녀석을 사용하려면 코루틴 스코프가 필요하다.

- UI 작업 O

-  Job을 반환한다

 

 

runBlocking

-  얘도 코루틴 빌더역할을 한다.

-  자식 스레드가 완료될 때 까지 현재 대기중인 스레드를 block한다. 

- 정규함수다

 

 


코루틴 Scope

 CoroutinScope 

 - (자식 스레드가 완료될 때 까지 현재 스레드를 block 하지 않는다.)

-  일시중단 함수다.

여러 동시 작업을 수행할 수 있다

 

 GlobalScope

- ( 전역으로 사용되는 스코프, 실행하는동안 일부 메모리 자원을 계속 소비 )

- 메인쓰레드가 종료되면 종료된다. (Like 데몬스레드 )

( 데몬 스레드는 일반 스레드가 모두 종료되면 더는 할 일이 없으므로, 데몬 스레드 역시 자동으로 종료됩니다.)

 

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

 


코루틴 Suspend function

suspend

 

delay 

- suspend 로 일시정지 한다  ( Thread.sleep은 쓰레드 블로킹을 한다는 점에서 차이가 있다 )

- 코루틴 스코프내, 다른 suspend 내에서 만 사용가능 

 

join()

- 다른 코루틴이 작동하는 동안 delay하는 것은 좋지 않은 접근 방법입니다.

- 백그라운드 작업이 완료될때까지 join()을 사용하여 명시적으로 기다려야합니다.

코루틴의 코드가 멈추는 경우 ( 예를 들어 너무 오랜 시간동안 delay되는 경우 ),

너무 많은 코루틴을 실행하여 메모리가 부족하면 어떻게 될까요?

즉, 실행된 모든 코루틴에 대한 참조를 수동으로 유지하고 이들을 join() 해야 하는 것은 오류가 발생하기 쉽습니다.

 

해결방법은 GlobalScope에서 coroutines (TOP 레벨 코루틴 )를 시작하는 대신

일반적으로 Thread( thread는 항상 전역 )와 마찬가지로, 수행중인 작업의 특정 범위에서 동시 루틴을 시작할 수 있습니다.

=> Top 레벨 코루틴을 만들지말고,  차일드 코루틴으로 하자 ( 부모코루틴이 기다려주기 때문에 )
 
runBlocking를 포함한 모든 코루틴 빌더는 CoroutineScope 인스턴스를 추가합니다. 

외부 코루틴에서는 범위 내에서 시작된 모든 코루틴이 완료 될 때까지 코루틴을 완료하지 않기 때문에 

명시적으로 처리하지 않고도 ( join() ) 이 범위에서 코루틴을 시작할 수 있습니다.

 

=>  Structured Concurrency (구조화된 동시성)

fun test4_1() = runBlocking {
    var job : Job = GlobalScope.launch {
         delay(1000L)
         Log.d("Woongs", "GlobalScope")
    }

    Log.d("Woongs", "main")
    job.join()
    // job이 완료될때까지 기다린다.
    // job이 많아지만... 다 join() 해줘야 하네.?
 }

// 개선 
// GlobalScope를 사용하지 않고 runBlocking 안에 launch를 이용 
fun main() = runBlocking { // this: CoroutineScope    
	launch { 
    	// launch new coroutine in the scope of runBlocking        
        delay(1000L)        
        println("World!")    
  	}
    println("Hello,")
}



// 예시2
 fun test4_2() = runBlocking {

        launch {
            delay(1000L)
            Log.d("Woongs", "Structured Concurrency 1")
        }

        launch {
            delay(1000L)
            Log.d("Woongs", "Structured Concurrency 2")
        }

        launch {
            delay(1000L)
            Log.d("Woongs", "Structured Concurrency 3")
        }

        launch {
            delay(1000L)
            Log.d("Woongs", "Structured Concurrency 4")
        }

        Log.d("Woongs", "main")

    }

 


* 일시정지, 재개되는지 확인해보기

 runBlocking {
            launch {
                repeat(5) { i ->
                    println("Coroutine A , $i")
                    btn_02Text = btn_02Text+"\nCoroutine A , $i"
                    delay(10L)
                }
            }

            launch {
                repeat(5) { i ->
                    println("Coroutine B , $i")
                    btn_02Text = btn_02Text+"\nCoroutine B , $i"
                    delay(10L)
                }
            }
            println("Coroutine Outer")
            btn_02Text = btn_02Text+"\nCoroutine Outer"
        }

 

 


참고

https://kotlinlang.org/docs/coroutines-basics.html#scope-builder

 

Coroutines basics | Kotlin

 

kotlinlang.org

https://eso0609.tistory.com/73?category=824962 

 

안드로이드 Kotlin Coroutines 정리 Part 1

Coroutin GlobalScope GlobalScope.launch { // launch new coroutine in background and continue delay(1000L) // non-blocking delay for 1 second (default time unit is ms) Log.e("coroutine","World!") //..

eso0609.tistory.com

https://www.youtube.com/watch?v=14AGUuh8Bp8&list=PLbJr8hAHHCP5N6Lsot8SAnC28SoxwAU5A&index=2 

 

728x90
반응형