GlobalScope

A global CoroutineScope not bound to any job. Global scope is used to launch top-level coroutines which are operating on the whole application lifetime and are not cancelled prematurely.

Active coroutines launched in GlobalScope do not keep the process alive. They are like daemon threads.

This is a delicate API. It is easy to accidentally create resource or memory leaks when GlobalScope is used. A coroutine launched in GlobalScope is not subject to the principle of structured concurrency, so if it hangs or gets delayed due to a problem (e.g. due to a slow network), it will stay working and consuming resources. For example, consider the following code:

fun loadConfiguration() {
GlobalScope.launch {
val config = fetchConfigFromServer() // network request
updateConfiguration(config)
}
}

A call to loadConfiguration creates a coroutine in the GlobalScope that works in background without any provision to cancel it or to wait for its completion. If a network is slow, it keeps waiting in background, consuming resources. Repeated calls to loadConfiguration will consume more and more resources.

Possible replacements

In many cases uses of GlobalScope should be removed, marking the containing operation with suspend, for example:

suspend fun loadConfiguration() {
val config = fetchConfigFromServer() // network request
updateConfiguration(config)
}

In cases when GlobalScope.launch was used to launch multiple concurrent operations, the corresponding operations shall be grouped with coroutineScope instead:

// concurrently load configuration and data
suspend fun loadConfigurationAndData() {
coroutineScope {
launch { loadConfiguration() }
launch { loadData() }
}
}

In top-level code, when launching a concurrent operation from a non-suspending context, an appropriately confined instance of CoroutineScope shall be used instead of a GlobalScope. See docs on CoroutineScope for details.

GlobalScope vs custom scope

Do not replace GlobalScope.launch { ... } with CoroutineScope().launch { ... } constructor function call. The latter has the same pitfalls as GlobalScope. See CoroutineScope documentation on the intended usage of CoroutineScope() constructor function.

Legitimate use-cases

There are limited circumstances under which GlobalScope can be legitimately and safely used, such as top-level background processes that must stay active for the whole duration of the application's lifetime. Because of that, any use of GlobalScope requires an explicit opt-in with @OptIn(DelicateCoroutinesApi::class), like this:

// A global coroutine to log statistics every second, must be always active
@OptIn(DelicateCoroutinesApi::class)
val globalScopeReporter = GlobalScope.launch {
while (true) {
delay(1000)
logStatistics()
}
}

Properties

Link copied to clipboard

Extensions

Link copied to clipboard
fun <E> CoroutineScope.actor(    context: CoroutineContext = EmptyCoroutineContext,     capacity: Int = 0,     start: CoroutineStart = CoroutineStart.DEFAULT,     onCompletion: CompletionHandler? = null,     block: suspend ActorScope<E>.() -> Unit): SendChannel<E>

Launches new coroutine that is receiving messages from its mailbox channel and returns a reference to its mailbox channel as a SendChannel. The resulting object can be used to send messages to this coroutine.

Link copied to clipboard
fun <T> CoroutineScope.async(    context: CoroutineContext = EmptyCoroutineContext,     start: CoroutineStart = CoroutineStart.DEFAULT,     block: suspend CoroutineScope.() -> T): Deferred<T>

Creates a coroutine and returns its future result as an implementation of Deferred. The running coroutine is cancelled when the resulting deferred is cancelled. The resulting coroutine has a key difference compared with similar primitives in other languages and frameworks: it cancels the parent job (or outer scope) on failure to enforce structured concurrency paradigm. To change that behaviour, supervising parent (SupervisorJob or supervisorScope) can be used.

Link copied to clipboard
fun <E> CoroutineScope.broadcast(    context: CoroutineContext = EmptyCoroutineContext,     capacity: Int = 1,     start: CoroutineStart = CoroutineStart.LAZY,     onCompletion: CompletionHandler? = null,     block: suspend ProducerScope<E>.() -> Unit): BroadcastChannel<E>

Launches new coroutine to produce a stream of values by sending them to a broadcast channel and returns a reference to the coroutine as a BroadcastChannel. The resulting object can be used to subscribe to elements produced by this coroutine.

Link copied to clipboard

Cancels this scope, including its job and all its children with an optional cancellation cause. A cause can be used to specify an error message or to provide other details on a cancellation reason for debugging purposes. Throws IllegalStateException if the scope does not have a job in it.

fun CoroutineScope.cancel(message: String, cause: Throwable? = null)

Cancels this scope, including its job and all its children with a specified diagnostic error message. A cause can be specified to provide additional details on a cancellation reason for debugging purposes. Throws IllegalStateException if the scope does not have a job in it.

Link copied to clipboard

Ensures that current scope is active.

Link copied to clipboard

Returns true when the current Job is still active (has not completed and was not cancelled yet).

Link copied to clipboard
fun CoroutineScope.launch(    context: CoroutineContext = EmptyCoroutineContext,     start: CoroutineStart = CoroutineStart.DEFAULT,     block: suspend CoroutineScope.() -> Unit): Job

Launches a new coroutine without blocking the current thread and returns a reference to the coroutine as a Job. The coroutine is cancelled when the resulting job is cancelled.

Link copied to clipboard

Creates a context for a new coroutine. It installs Dispatchers.Default when no other dispatcher or ContinuationInterceptor is specified and adds optional support for debugging facilities (when turned on) and copyable-thread-local facilities on JVM.

Creates a context for a new coroutine. It installs Dispatchers.Default when no other dispatcher or ContinuationInterceptor is specified and adds optional support for debugging facilities (when turned on) and copyable-thread-local facilities on JVM. See DEBUG_PROPERTY_NAME for description of debugging facilities on JVM.

Link copied to clipboard

Adds the specified coroutine context to this scope, overriding existing elements in the current scope's context with the corresponding keys.

Link copied to clipboard
fun <E> CoroutineScope.produce(    context: CoroutineContext = EmptyCoroutineContext,     capacity: Int = 0,     block: suspend ProducerScope<E>.() -> Unit): ReceiveChannel<E>

Launches a new coroutine to produce a stream of values by sending them to a channel and returns a reference to the coroutine as a ReceiveChannel. This resulting object can be used to receive elements produced by this coroutine.

Link copied to clipboard
fun <T> CoroutineScope.promise(    context: CoroutineContext = EmptyCoroutineContext,     start: CoroutineStart = CoroutineStart.DEFAULT,     block: suspend CoroutineScope.() -> T): Promise<T>

Starts new coroutine and returns its result as an implementation of Promise.