@@ -57,24 +57,24 @@ They are launched with [launch] _coroutine builder_ in a context of some [Corout
5757Here we are launching a new coroutine in the [ GlobalScope] , meaning that the lifetime of the new
5858coroutine is limited only by the lifetime of the whole application.
5959
60- You can achieve the same result replacing
61- ` GlobalScope.launch { ... } ` with ` thread { ... } ` and ` delay(...) ` with ` Thread.sleep(...) ` .
60+ You can achieve the same result by replacing
61+ ` GlobalScope.launch { ... } ` with ` thread { ... } ` , and ` delay(...) ` with ` Thread.sleep(...) ` .
6262Try it (don't forget to import ` kotlin.concurrent.thread ` ).
6363
64- If you start by replacing ` GlobalScope.launch ` by ` thread ` , the compiler produces the following error:
64+ If you start by replacing ` GlobalScope.launch ` with ` thread ` , the compiler produces the following error:
6565
6666```
6767Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another suspend function
6868```
6969
70- That is because [ delay] is a special _ suspending function_ that does not block a thread, but _ suspends_
71- coroutine and it can be only used from a coroutine.
70+ That is because [ delay] is a special _ suspending function_ that does not block a thread, but _ suspends_ the
71+ coroutine, and it can be only used from a coroutine.
7272
7373### Bridging blocking and non-blocking worlds
7474
7575The first example mixes _ non-blocking_ ` delay(...) ` and _ blocking_ ` Thread.sleep(...) ` in the same code.
7676It is easy to lose track of which one is blocking and which one is not.
77- Let's be explicit about blocking using [ runBlocking] coroutine builder:
77+ Let's be explicit about blocking using the [ runBlocking] coroutine builder:
7878
7979<div class =" sample " markdown =" 1 " theme =" idea " data-min-compiler-version =" 1.3 " >
8080
@@ -195,15 +195,15 @@ the background job in any way. Much better.
195195There is still something to be desired for practical usage of coroutines.
196196When we use ` GlobalScope.launch ` , we create a top-level coroutine. Even though it is light-weight, it still
197197consumes some memory resources while it runs. If we forget to keep a reference to the newly launched
198- coroutine it still runs. What if the code in the coroutine hangs (for example, we erroneously
198+ coroutine, it still runs. What if the code in the coroutine hangs (for example, we erroneously
199199delay for too long), what if we launched too many coroutines and ran out of memory?
200200Having to manually keep references to all the launched coroutines and [ join] [ Job.join ] them is error-prone.
201201
202202There is a better solution. We can use structured concurrency in our code.
203203Instead of launching coroutines in the [ GlobalScope] , just like we usually do with threads (threads are always global),
204204we can launch coroutines in the specific scope of the operation we are performing.
205205
206- In our example, we have ` main ` function that is turned into a coroutine using [ runBlocking] coroutine builder.
206+ In our example, we have a ` main ` function that is turned into a coroutine using the [ runBlocking] coroutine builder.
207207Every coroutine builder, including ` runBlocking ` , adds an instance of [ CoroutineScope] to the scope of its code block.
208208We can launch coroutines in this scope without having to ` join ` them explicitly, because
209209an outer coroutine (` runBlocking ` in our example) does not complete until all the coroutines launched
@@ -233,12 +233,12 @@ World!
233233-->
234234
235235### Scope builder
236- In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using
237- [ coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children
238- complete.
239236
240- [ runBlocking] and [ coroutineScope] may look similar because they both wait for its body and all its children to complete.
241- The main difference between these two is that the [ runBlocking] method _ blocks_ the current thread for waiting,
237+ In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using the
238+ [ coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children complete.
239+
240+ [ runBlocking] and [ coroutineScope] may look similar because they both wait for their body and all its children to complete.
241+ The main difference is that the [ runBlocking] method _ blocks_ the current thread for waiting,
242242while [ coroutineScope] just suspends, releasing the underlying thread for other usages.
243243Because of that difference, [ runBlocking] is a regular function and [ coroutineScope] is a suspending function.
244244
@@ -280,16 +280,16 @@ Task from nested launch
280280Coroutine scope is over
281281-->
282282
283- Note that right after "Task from coroutine scope" message, while waiting for nested launch,
284- "Task from runBlocking" is executed and printed, though coroutineScope is not completed yet.
283+ Note that right after the "Task from coroutine scope" message ( while waiting for nested launch)
284+ "Task from runBlocking" is executed and printed — even though the [ coroutineScope] is not completed yet.
285285
286286### Extract function refactoring
287287
288288Let's extract the block of code inside ` launch { ... } ` into a separate function. When you
289- perform "Extract function" refactoring on this code you get a new function with ` suspend ` modifier.
290- That is your first _ suspending function_ . Suspending functions can be used inside coroutines
289+ perform "Extract function" refactoring on this code, you get a new function with the ` suspend ` modifier.
290+ This is your first _ suspending function_ . Suspending functions can be used inside coroutines
291291just like regular functions, but their additional feature is that they can, in turn,
292- use other suspending functions, like ` delay ` in this example, to _ suspend_ execution of a coroutine.
292+ use other suspending functions ( like ` delay ` in this example) to _ suspend_ execution of a coroutine.
293293
294294<div class =" sample " markdown =" 1 " theme =" idea " data-min-compiler-version =" 1.3 " >
295295
@@ -319,11 +319,11 @@ World!
319319
320320
321321But what if the extracted function contains a coroutine builder which is invoked on the current scope?
322- In this case ` suspend ` modifier on the extracted function is not enough. Making ` doWorld ` an extension
323- method on ` CoroutineScope ` is one of the solutions, but it may not always be applicable as it does not make API clearer.
322+ In this case, the ` suspend ` modifier on the extracted function is not enough. Making ` doWorld ` an extension
323+ method on ` CoroutineScope ` is one of the solutions, but it may not always be applicable as it does not make the API clearer.
324324The idiomatic solution is to have either an explicit ` CoroutineScope ` as a field in a class containing the target function
325325or an implicit one when the outer class implements ` CoroutineScope ` .
326- As a last resort, [ CoroutineScope(coroutineContext)] [ CoroutineScope() ] can be used, but such approach is structurally unsafe
326+ As a last resort, [ CoroutineScope(coroutineContext)] [ CoroutineScope() ] can be used, but such an approach is structurally unsafe
327327because you no longer have control on the scope of execution of this method. Only private APIs can use this builder.
328328
329329### Coroutines ARE light-weight
@@ -352,6 +352,7 @@ fun main() = runBlocking {
352352<!-- - TEST lines.size == 1 && lines[0] == ".".repeat(100_000) -->
353353
354354It launches 100K coroutines and, after a second, each coroutine prints a dot.
355+
355356Now, try that with threads. What would happen? (Most likely your code will produce some sort of out-of-memory error)
356357
357358### Global coroutines are like daemon threads
0 commit comments