There is still something to be desired for practical usage of
coroutines. When we use GlobalScope.launch
we create a top-level
coroutine. Even though it is light-weight, it still consumes some
memory resources while it runs. If we forget to keep a reference to
the newly launched coroutine it still runs. What if the code in the
coroutine hangs (for example, we erroneously delay for too long), what
if we launched too many coroutines and ran out of memory? Having to
manually keep a reference to all the launched coroutines and join them
is error-prone.
There is a better solution. We can use structured concurrency in our
code. Instead of launching coroutines in the GlobalScope
, just like we
usually do with threads (threads are always global), we can launch
coroutines in the specific scope of the operation we are performing.
In our example, we have main function that is turned into a coroutine
using runBlocking
coroutine builder. Every coroutine builder,
including runBlocking
, adds an instance of CoroutineScope
to the scope
of its code block. We can launch coroutines in this scope without
having to join them explicitly, because an outer coroutine
(runBlocking
in our example) does not complete until all the
coroutines launched in its scope complete. Thus, we can make our
example simpler:
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
GlobalScope
中使用并忽略内部异常确实不是一个好的模式。 - marstranDispatchers.Default
,例如。 - undefined