GlobalScope vs CoroutineScope()

이태훈·2022년 3월 6일
1

안녕하세요. 이번에는 GlobalScope와 CoroutineScope의 차이점에 대해 알아보겠습니다.

포스팅에 앞서, CoroutineContext에 대해 어느정도 이해를 가지고 보시는 것을 추천드립니다.

먼저, GlobalScope와 CoroutineScope()의 코드를 한번 보겠습니다.

public object GlobalScope : CoroutineScope {
    /**
     * Returns [EmptyCoroutineContext].
     */
    override val coroutineContext: CoroutineContext
        get() = EmptyCoroutineContext
}

public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
    ContextScope(if (context[Job] != null) context else context + Job())

GlobalScope는 EmptyCoroutineContext를 CoroutineContext로 사용하고 있고, CoroutineScope()는 CoroutineContext가 강제되고, 넘겨 받은 CoroutineContext에 Job이 없으면 추가해주는 것을 볼 수 있습니다.

public object EmptyCoroutineContext : CoroutineContext, Serializable {
    private const val serialVersionUID: Long = 0
    private fun readResolve(): Any = EmptyCoroutineContext

    public override fun <E : Element> get(key: Key<E>): E? = null
    public override fun <R> fold(initial: R, operation: (R, Element) -> R): R = initial
    public override fun plus(context: CoroutineContext): CoroutineContext = context
    public override fun minusKey(key: Key<*>): CoroutineContext = this
    public override fun hashCode(): Int = 0
    public override fun toString(): String = "EmptyCoroutineContext"
}

internal class ContextScope(context: CoroutineContext) : CoroutineScope {
    override val coroutineContext: CoroutineContext = context
    // CoroutineScope is used intentionally for user-friendly representation
    override fun toString(): String = "CoroutineScope(coroutineContext=$coroutineContext)"
}

readResolve() 함수에 대해서는 [Kotlin] Signleton Serialization 을 보시면 됩니다.
간략하게는, Signleton Object가 재생성이 되는 것을 방지하는 함수입니다.

EmptryCoroutineContext를 보면 CoroutineContext의 Element가 아무것도 없는 것을 볼 수 있습니다.

반면에, ContextScope는 파라미터로 넘겨받은 CoroutineContext를 사용하는 것을 볼 수 있죠.

여기서, GlobalScope와 CoroutineScope()는 GlobalScope가 Signleton인 점, CoroutineContext의 Element 유무 말고는 차이점이 없는 것을 볼 수 있습니다.

먼저, GlobalScope가 Signleton이기 때문에 생기는 차이점에 대해 알아보겠습니다.

  • GlobalScope는 Signleton이기 때문에 Application이 살아있는 동안은 계속 살아있습니다.
  • CoroutineScope()는 객체를 생성하기 때문에 호출한 객체가 메모리에서 해제가 되면 같이 파괴가 됩니다. 하지만, 원하는 대로 작동하려면 적절하게 cancel을 호출해줘야 해당 코루틴 작업이 취소됩니다.

다음으로, CoroutineContext의 유무 때문에 생기는 차이점에 대해 알아보겠습니다.

  • Dispatcher : EmptyCoroutineContext로 코루틴 람다를 실행하면 기본적으로 Dispatchers.Default를 지정해줍니다. 그래서, GlobalScope.launch {} 를 하면 Dispatcher.Default로 지정되어 코루틴 람다를 실행하게 되고, CoroutineScope는 생성할 때 넘겨준 Dispatcher로 실행하게 됩니다.
  • Job : GlobalScope는 Job이 없는 CoroutineContext를 가지고 있기 때문에, GlobalScope.cancel() 이런 식으로 코루틴 작업을 취소할 수 없습니다. 따라서, GlobalScope.launch 에서 반환되는 job을 가지고만 취소를 해야합니다. 반대로, CoroutineScope()는 생성할 때 Job이 있는지 체크하여 없으면 Job을 넣어주기 때문에, 바로 cancel이 가능합니다.
profile
https://www.linkedin.com/in/%ED%83%9C%ED%9B%88-%EC%9D%B4-7b9563237

0개의 댓글