GlobalScope
A global CoroutineScope not bound to any job. Global scope is used to launch top-level coroutines that operate throughout the application's lifetime and are not canceled 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 the background without any provision to cancel it or to wait for its completion. If a network is slow, it keeps waiting in the background, consuming resources. Repeated calls to loadConfiguration
will consume more and more resources.
Possible replacements
In many circumstances, uses of 'GlobalScope' should be removed, with the containing operation marked as '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 GlobalScope
. See docs on CoroutineScope for details.
GlobalScope vs. Custom CoroutineScope
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
Returns EmptyCoroutineContext.