blob: ca34fdfad253f72bd6f0735eb54d44a30204b8c3 [file] [log] [blame] [view]
hadihariri7db55532018-09-15 10:35:08 +02001<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt
2/*
3 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
4 */
5
6// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarov0950dfa2018-07-13 10:33:25 +03007package kotlinx.coroutines.guide.$$1$$2
hadihariri7db55532018-09-15 10:35:08 +02008-->
9<!--- KNIT ../core/kotlinx-coroutines-core/test/guide/.*\.kt -->
10<!--- TEST_OUT ../core/kotlinx-coroutines-core/test/guide/test/ComposingGuideTest.kt
11// This file was automatically generated from coroutines-guide.md by Knit tool. Do not edit.
Roman Elizarov0950dfa2018-07-13 10:33:25 +030012package kotlinx.coroutines.guide.test
hadihariri7db55532018-09-15 10:35:08 +020013
14import org.junit.Test
15
16class ComposingGuideTest {
17-->
18
19## Table of contents
20
21<!--- TOC -->
22
23* [Composing suspending functions](#composing-suspending-functions)
24 * [Sequential by default](#sequential-by-default)
25 * [Concurrent using async](#concurrent-using-async)
26 * [Lazily started async](#lazily-started-async)
27 * [Async-style functions](#async-style-functions)
28 * [Structured concurrency with async](#structured-concurrency-with-async)
29
30<!--- END_TOC -->
31
32## Composing suspending functions
33
34This section covers various approaches to composition of suspending functions.
35
36### Sequential by default
37
38Assume that we have two suspending functions defined elsewhere that do something useful like some kind of
39remote service call or computation. We just pretend they are useful, but actually each one just
40delays for a second for the purpose of this example:
41
Alexander Prendotacbeef102018-09-27 18:42:04 +030042<div class="sample" markdown="1" theme="idea" data-highlight-only>
43
hadihariri7db55532018-09-15 10:35:08 +020044```kotlin
45suspend fun doSomethingUsefulOne(): Int {
46 delay(1000L) // pretend we are doing something useful here
47 return 13
48}
49
50suspend fun doSomethingUsefulTwo(): Int {
51 delay(1000L) // pretend we are doing something useful here, too
52 return 29
53}
54```
55
Alexander Prendotacbeef102018-09-27 18:42:04 +030056</div>
57
hadihariri7db55532018-09-15 10:35:08 +020058
59What do we do if need to invoke them _sequentially_ -- first `doSomethingUsefulOne` _and then_
60`doSomethingUsefulTwo` and compute the sum of their results?
61In practice we do this if we use the results of the first function to make a decision on whether we need
62to invoke the second one or to decide on how to invoke it.
63
64We use a normal sequential invocation, because the code in the coroutine, just like in the regular
65code, is _sequential_ by default. The following example demonstrates it by measuring the total
66time it takes to execute both suspending functions:
67
Prendota65e6c8c2018-10-17 11:51:08 +030068<!--- CLEAR -->
69
70<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +030071
hadihariri7db55532018-09-15 10:35:08 +020072```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +030073import kotlinx.coroutines.*
74import kotlin.system.*
75
76fun main() = runBlocking<Unit> {
77//sampleStart
hadihariri7db55532018-09-15 10:35:08 +020078 val time = measureTimeMillis {
79 val one = doSomethingUsefulOne()
80 val two = doSomethingUsefulTwo()
81 println("The answer is ${one + two}")
82 }
83 println("Completed in $time ms")
Prendota65e6c8c2018-10-17 11:51:08 +030084//sampleEnd
85}
86
87suspend fun doSomethingUsefulOne(): Int {
88 delay(1000L) // pretend we are doing something useful here
89 return 13
90}
91
92suspend fun doSomethingUsefulTwo(): Int {
93 delay(1000L) // pretend we are doing something useful here, too
94 return 29
hadihariri7db55532018-09-15 10:35:08 +020095}
96```
97
Alexander Prendotacbeef102018-09-27 18:42:04 +030098</div>
99
hadihariri7db55532018-09-15 10:35:08 +0200100> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-compose-01.kt)
101
102It produces something like this:
103
104```text
105The answer is 42
106Completed in 2017 ms
107```
108
109<!--- TEST ARBITRARY_TIME -->
110
111### Concurrent using async
112
113What if there are no dependencies between invocation of `doSomethingUsefulOne` and `doSomethingUsefulTwo` and
114we want to get the answer faster, by doing both _concurrently_? This is where [async] comes to help.
115
116Conceptually, [async] is just like [launch]. It starts a separate coroutine which is a light-weight thread
117that works concurrently with all the other coroutines. The difference is that `launch` returns a [Job] and
118does not carry any resulting value, while `async` returns a [Deferred] -- a light-weight non-blocking future
119that represents a promise to provide a result later. You can use `.await()` on a deferred value to get its eventual result,
120but `Deferred` is also a `Job`, so you can cancel it if needed.
121
Alexander Prendotacbeef102018-09-27 18:42:04 +0300122
Prendota65e6c8c2018-10-17 11:51:08 +0300123<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300124
hadihariri7db55532018-09-15 10:35:08 +0200125```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300126import kotlinx.coroutines.*
127import kotlin.system.*
128
129fun main() = runBlocking<Unit> {
130//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200131 val time = measureTimeMillis {
132 val one = async { doSomethingUsefulOne() }
133 val two = async { doSomethingUsefulTwo() }
134 println("The answer is ${one.await() + two.await()}")
135 }
136 println("Completed in $time ms")
Prendota65e6c8c2018-10-17 11:51:08 +0300137//sampleEnd
138}
139
140suspend fun doSomethingUsefulOne(): Int {
141 delay(1000L) // pretend we are doing something useful here
142 return 13
143}
144
145suspend fun doSomethingUsefulTwo(): Int {
146 delay(1000L) // pretend we are doing something useful here, too
147 return 29
hadihariri7db55532018-09-15 10:35:08 +0200148}
149```
150
Alexander Prendotacbeef102018-09-27 18:42:04 +0300151</div>
152
hadihariri7db55532018-09-15 10:35:08 +0200153> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-compose-02.kt)
154
155It produces something like this:
156
157```text
158The answer is 42
159Completed in 1017 ms
160```
161
162<!--- TEST ARBITRARY_TIME -->
163
164This is twice as fast, because we have concurrent execution of two coroutines.
165Note, that concurrency with coroutines is always explicit.
166
167### Lazily started async
168
169There is a laziness option to [async] using an optional `start` parameter with a value of [CoroutineStart.LAZY].
170It starts coroutine only when its result is needed by some
171[await][Deferred.await] or if a [start][Job.start] function
172is invoked. Run the following example:
173
Prendota65e6c8c2018-10-17 11:51:08 +0300174<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300175
hadihariri7db55532018-09-15 10:35:08 +0200176```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300177import kotlinx.coroutines.*
178import kotlin.system.*
179
180fun main() = runBlocking<Unit> {
181//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200182 val time = measureTimeMillis {
183 val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
184 val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
185 // some computation
186 one.start() // start the first one
187 two.start() // start the second one
188 println("The answer is ${one.await() + two.await()}")
189 }
190 println("Completed in $time ms")
Prendota65e6c8c2018-10-17 11:51:08 +0300191//sampleEnd
192}
193
194suspend fun doSomethingUsefulOne(): Int {
195 delay(1000L) // pretend we are doing something useful here
196 return 13
197}
198
199suspend fun doSomethingUsefulTwo(): Int {
200 delay(1000L) // pretend we are doing something useful here, too
201 return 29
hadihariri7db55532018-09-15 10:35:08 +0200202}
203```
204
Alexander Prendotacbeef102018-09-27 18:42:04 +0300205</div>
206
hadihariri7db55532018-09-15 10:35:08 +0200207> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-compose-03.kt)
208
209It produces something like this:
210
211```text
212The answer is 42
213Completed in 1017 ms
214```
215
216<!--- TEST ARBITRARY_TIME -->
217
218So, here the two coroutines are defined but not executed as in the previous example, but the control is given to
219the programmer on when exactly to start the execution by calling [start][Job.start]. We first
220start `one`, then start `two`, and then await for the individual coroutines to finish.
221
222Note, that if we have called [await][Deferred.await] in `println` and omitted [start][Job.start] on individual
223coroutines, then we would have got the sequential behaviour as [await][Deferred.await] starts the coroutine
224execution and waits for the execution to finish, which is not the intended use-case for laziness.
225The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the
226standard `lazy` function in cases when computation of the value involves suspending functions.
227
228### Async-style functions
229
230We can define async-style functions that invoke `doSomethingUsefulOne` and `doSomethingUsefulTwo`
231_asynchronously_ using [async] coroutine builder with an explicit [GlobalScope] reference.
232We name such functions with
233"Async" suffix to highlight the fact that they only start asynchronous computation and one needs
234to use the resulting deferred value to get the result.
235
Alexander Prendotacbeef102018-09-27 18:42:04 +0300236<div class="sample" markdown="1" theme="idea" data-highlight-only>
237
hadihariri7db55532018-09-15 10:35:08 +0200238```kotlin
239// The result type of somethingUsefulOneAsync is Deferred<Int>
240fun somethingUsefulOneAsync() = GlobalScope.async {
241 doSomethingUsefulOne()
242}
243
244// The result type of somethingUsefulTwoAsync is Deferred<Int>
245fun somethingUsefulTwoAsync() = GlobalScope.async {
246 doSomethingUsefulTwo()
247}
248```
249
Alexander Prendotacbeef102018-09-27 18:42:04 +0300250</div>
251
hadihariri7db55532018-09-15 10:35:08 +0200252Note, that these `xxxAsync` functions are **not** _suspending_ functions. They can be used from anywhere.
253However, their use always implies asynchronous (here meaning _concurrent_) execution of their action
254with the invoking code.
255
256The following example shows their use outside of coroutine:
Alexander Prendotacbeef102018-09-27 18:42:04 +0300257
Prendota65e6c8c2018-10-17 11:51:08 +0300258<!--- CLEAR -->
259
260<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
hadihariri7db55532018-09-15 10:35:08 +0200261
262```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300263import kotlinx.coroutines.*
264import kotlin.system.*
265
266//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200267// note, that we don't have `runBlocking` to the right of `main` in this example
Prendota65e6c8c2018-10-17 11:51:08 +0300268fun main() {
hadihariri7db55532018-09-15 10:35:08 +0200269 val time = measureTimeMillis {
270 // we can initiate async actions outside of a coroutine
271 val one = somethingUsefulOneAsync()
272 val two = somethingUsefulTwoAsync()
273 // but waiting for a result must involve either suspending or blocking.
274 // here we use `runBlocking { ... }` to block the main thread while waiting for the result
275 runBlocking {
276 println("The answer is ${one.await() + two.await()}")
277 }
278 }
279 println("Completed in $time ms")
280}
Prendota65e6c8c2018-10-17 11:51:08 +0300281//sampleEnd
282
283fun somethingUsefulOneAsync() = GlobalScope.async {
284 doSomethingUsefulOne()
285}
286
287fun somethingUsefulTwoAsync() = GlobalScope.async {
288 doSomethingUsefulTwo()
289}
290
291suspend fun doSomethingUsefulOne(): Int {
292 delay(1000L) // pretend we are doing something useful here
293 return 13
294}
295
296suspend fun doSomethingUsefulTwo(): Int {
297 delay(1000L) // pretend we are doing something useful here, too
298 return 29
299}
hadihariri7db55532018-09-15 10:35:08 +0200300```
301
Alexander Prendotacbeef102018-09-27 18:42:04 +0300302</div>
303
hadihariri7db55532018-09-15 10:35:08 +0200304> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-compose-04.kt)
305
306<!--- TEST ARBITRARY_TIME
307The answer is 42
308Completed in 1085 ms
309-->
310
311> This programming style with async functions is provided here only for illustration, because it is a popular style
312in other programming languages. Using this style with Kotlin coroutines is **strongly discouraged** for the
313reasons that are explained below.
314
315Consider what happens if between `val one = somethingUsefulOneAsync()` line and `one.await()` expression there is some logic
316error in the code and the program throws an exception and the operation that was being performed by the program aborts.
317Normally, a global error-handler could catch this exception, log and report the error for developers, but the program
318could otherwise continue doing other operations. But here we have `somethingUsefulOneAsync` still running in background,
319despite the fact, that operation that had initiated it aborts. This problem does not happen with structured
320concurrency, as shown in the section below.
321
322### Structured concurrency with async
323
324Let us take [Concurrent using async](#concurrent-using-async) example and extract a function that
325concurrently performs `doSomethingUsefulOne` and `doSomethingUsefulTwo` and returns the sum of their results.
326Because [async] coroutines builder is defined as extension on [CoroutineScope] we need to have it in the
327scope and that is what [coroutineScope] function provides:
328
Alexander Prendotacbeef102018-09-27 18:42:04 +0300329<div class="sample" markdown="1" theme="idea" data-highlight-only>
330
hadihariri7db55532018-09-15 10:35:08 +0200331```kotlin
332suspend fun concurrentSum(): Int = coroutineScope {
333 val one = async { doSomethingUsefulOne() }
334 val two = async { doSomethingUsefulTwo() }
hadihariri7db55532018-09-15 10:35:08 +0200335 one.await() + two.await()
336}
337```
338
Alexander Prendotacbeef102018-09-27 18:42:04 +0300339</div>
340
hadihariri7db55532018-09-15 10:35:08 +0200341This way, if something goes wrong inside the code of `concurrentSum` function and it throws an exception,
342all the coroutines that were launched in its scope are cancelled.
Alexander Prendotacbeef102018-09-27 18:42:04 +0300343
Prendota65e6c8c2018-10-17 11:51:08 +0300344<!--- CLEAR -->
345
346<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
hadihariri7db55532018-09-15 10:35:08 +0200347
348```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300349import kotlinx.coroutines.*
350import kotlin.system.*
351
352fun main() = runBlocking<Unit> {
353//sampleStart
hadihariri7db55532018-09-15 10:35:08 +0200354 val time = measureTimeMillis {
355 println("The answer is ${concurrentSum()}")
356 }
357 println("Completed in $time ms")
Prendota65e6c8c2018-10-17 11:51:08 +0300358//sampleEnd
359}
360
361suspend fun concurrentSum(): Int = coroutineScope {
362 val one = async { doSomethingUsefulOne() }
363 val two = async { doSomethingUsefulTwo() }
364 one.await() + two.await()
365}
366
367suspend fun doSomethingUsefulOne(): Int {
368 delay(1000L) // pretend we are doing something useful here
369 return 13
370}
371
372suspend fun doSomethingUsefulTwo(): Int {
373 delay(1000L) // pretend we are doing something useful here, too
374 return 29
hadihariri7db55532018-09-15 10:35:08 +0200375}
376```
377
Alexander Prendotacbeef102018-09-27 18:42:04 +0300378</div>
379
hadihariri7db55532018-09-15 10:35:08 +0200380> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-compose-05.kt)
381
382We still have concurrent execution of both operations as evident from the output of the above main function:
383
384```text
385The answer is 42
386Completed in 1017 ms
387```
388
389<!--- TEST ARBITRARY_TIME -->
390
391Cancellation is always propagated through coroutines hierarchy:
392
Prendota65e6c8c2018-10-17 11:51:08 +0300393<!--- CLEAR -->
394
395<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
Alexander Prendotacbeef102018-09-27 18:42:04 +0300396
hadihariri7db55532018-09-15 10:35:08 +0200397```kotlin
Prendota65e6c8c2018-10-17 11:51:08 +0300398import kotlinx.coroutines.*
399
400fun main() = runBlocking<Unit> {
hadihariri7db55532018-09-15 10:35:08 +0200401 try {
402 failedConcurrentSum()
403 } catch(e: ArithmeticException) {
404 println("Computation failed with ArithmeticException")
405 }
406}
407
408suspend fun failedConcurrentSum(): Int = coroutineScope {
409 val one = async<Int> {
410 try {
411 delay(Long.MAX_VALUE) // Emulates very long computation
412 42
413 } finally {
414 println("First child was cancelled")
415 }
416 }
417 val two = async<Int> {
418 println("Second child throws an exception")
419 throw ArithmeticException()
420 }
Vsevolod Tolstopyatovfac516f2018-09-28 14:38:29 +0300421 one.await() + two.await()
hadihariri7db55532018-09-15 10:35:08 +0200422}
423```
424
Alexander Prendotacbeef102018-09-27 18:42:04 +0300425</div>
426
hadihariri7db55532018-09-15 10:35:08 +0200427> You can get full code [here](../core/kotlinx-coroutines-core/test/guide/example-compose-06.kt)
428
429Note, how both first `async` and awaiting parent are cancelled on the one child failure:
430```text
431Second child throws an exception
432First child was cancelled
433Computation failed with ArithmeticException
434```
435
436<!--- TEST -->
437
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300438<!--- MODULE kotlinx-coroutines-core -->
Roman Elizarov0950dfa2018-07-13 10:33:25 +0300439<!--- INDEX kotlinx.coroutines -->
440[async]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
441[launch]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
442[Job]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
443[Deferred]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html
444[CoroutineStart.LAZY]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/-l-a-z-y.html
445[Deferred.await]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/await.html
446[Job.start]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/start.html
447[GlobalScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/index.html
448[CoroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
449[coroutineScope]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
Roman Elizarov99c28aa2018-09-23 18:42:36 +0300450<!--- END -->