xref: /aosp_15_r20/external/kotlinx.coroutines/docs/topics/coroutines-basics.md (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)
1<!--- TEST_NAME BasicsGuideTest -->
2
3[//]: # (title: Coroutines basics)
4
5This section covers basic coroutine concepts.
6
7## Your first coroutine
8
9A _coroutine_ is an instance of a suspendable computation. It is conceptually similar to a thread, in the sense that it
10takes a block of code to run that works concurrently with the rest of the code.
11However, a coroutine is not bound to any particular thread. It may suspend its execution in one thread and resume in another one.
12
13Coroutines can be thought of as light-weight threads, but there is a number
14of important differences that make their real-life usage very different from threads.
15
16Run the following code to get to your first working coroutine:
17
18```kotlin
19import kotlinx.coroutines.*
20
21//sampleStart
22fun main() = runBlocking { // this: CoroutineScope
23    launch { // launch a new coroutine and continue
24        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
25        println("World!") // print after delay
26    }
27    println("Hello") // main coroutine continues while a previous one is delayed
28}
29//sampleEnd
30```
31{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
32
33> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-01.kt).
34>
35{type="note"}
36
37You will see the following result:
38
39```text
40Hello
41World!
42```
43
44<!--- TEST -->
45
46Let's dissect what this code does.
47
48[launch] is a _coroutine builder_. It launches a new coroutine concurrently with
49the rest of the code, which continues to work independently. That's why `Hello` has been printed first.
50
51[delay] is a special _suspending function_. It _suspends_ the coroutine for a specific time. Suspending a coroutine
52does not _block_ the underlying thread, but allows other coroutines to run and use the underlying thread for
53their code.
54
55[runBlocking] is also a coroutine builder that bridges the non-coroutine world of a regular `fun main()` and
56the code with coroutines inside of `runBlocking { ... }` curly braces. This is highlighted in an IDE by
57`this: CoroutineScope` hint right after the `runBlocking` opening curly brace.
58
59If you remove or forget `runBlocking` in this code, you'll get an error on the [launch] call, since `launch`
60is declared only on the [CoroutineScope]:
61
62```Plain Text
63Unresolved reference: launch
64```
65
66The name of `runBlocking` means that the thread that runs it (in this case &mdash; the main thread) gets _blocked_ for
67the duration of the call, until all the coroutines inside `runBlocking { ... }` complete their execution. You will
68often see `runBlocking` used like that at the very top-level of the application and quite rarely inside the real code,
69as threads are expensive resources and blocking them is inefficient and is often not desired.
70
71### Structured concurrency
72
73Coroutines follow a principle of
74**structured concurrency** which means that new coroutines can only be launched in a specific [CoroutineScope]
75which delimits the lifetime of the coroutine. The above example shows that [runBlocking] establishes the corresponding
76scope and that is why the previous example waits until `World!` is printed after a second's delay and only then exits.
77
78In a real application, you will be launching a lot of coroutines. Structured concurrency ensures that they are not
79lost and do not leak. An outer scope cannot complete until all its children coroutines complete.
80Structured concurrency also ensures that any errors in the code are properly reported and are never lost.
81
82## Extract function refactoring
83
84Let's extract the block of code inside `launch { ... }` into a separate function. When you
85perform "Extract function" refactoring on this code, you get a new function with the `suspend` modifier.
86This is your first _suspending function_. Suspending functions can be used inside coroutines
87just like regular functions, but their additional feature is that they can, in turn,
88use other suspending functions (like `delay` in this example) to _suspend_ execution of a coroutine.
89
90```kotlin
91import kotlinx.coroutines.*
92
93//sampleStart
94fun main() = runBlocking { // this: CoroutineScope
95    launch { doWorld() }
96    println("Hello")
97}
98
99// this is your first suspending function
100suspend fun doWorld() {
101    delay(1000L)
102    println("World!")
103}
104//sampleEnd
105```
106{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
107
108> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-02.kt).
109>
110{type="note"}
111
112<!--- TEST
113Hello
114World!
115-->
116
117## Scope builder
118
119In addition to the coroutine scope provided by different builders, it is possible to declare your own scope using the
120[coroutineScope][_coroutineScope] builder. It creates a coroutine scope and does not complete until all launched children complete.
121
122[runBlocking] and [coroutineScope][_coroutineScope] builders may look similar because they both wait for their body and all its children to complete.
123The main difference is that the [runBlocking] method _blocks_ the current thread for waiting,
124while [coroutineScope][_coroutineScope] just suspends, releasing the underlying thread for other usages.
125Because of that difference, [runBlocking] is a regular function and [coroutineScope][_coroutineScope] is a suspending function.
126
127You can use `coroutineScope` from any suspending function.
128For example, you can move the concurrent printing of `Hello` and `World` into a `suspend fun doWorld()` function:
129
130```kotlin
131import kotlinx.coroutines.*
132
133//sampleStart
134fun main() = runBlocking {
135    doWorld()
136}
137
138suspend fun doWorld() = coroutineScope {  // this: CoroutineScope
139    launch {
140        delay(1000L)
141        println("World!")
142    }
143    println("Hello")
144}
145//sampleEnd
146```
147{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
148
149> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-03.kt).
150>
151{type="note"}
152
153This code also prints:
154
155```text
156Hello
157World!
158```
159
160<!--- TEST -->
161
162## Scope builder and concurrency
163
164A [coroutineScope][_coroutineScope] builder can be used inside any suspending function to perform multiple concurrent operations.
165Let's launch two concurrent coroutines inside a `doWorld` suspending function:
166
167```kotlin
168import kotlinx.coroutines.*
169
170//sampleStart
171// Sequentially executes doWorld followed by "Done"
172fun main() = runBlocking {
173    doWorld()
174    println("Done")
175}
176
177// Concurrently executes both sections
178suspend fun doWorld() = coroutineScope { // this: CoroutineScope
179    launch {
180        delay(2000L)
181        println("World 2")
182    }
183    launch {
184        delay(1000L)
185        println("World 1")
186    }
187    println("Hello")
188}
189//sampleEnd
190```
191{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
192
193> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-04.kt).
194>
195{type="note"}
196
197Both pieces of code inside `launch { ... }` blocks execute _concurrently_, with
198`World 1` printed first, after a second from start, and `World 2` printed next, after two seconds from start.
199A [coroutineScope][_coroutineScope] in `doWorld` completes only after both are complete, so `doWorld` returns and
200allows `Done` string to be printed only after that:
201
202```text
203Hello
204World 1
205World 2
206Done
207```
208
209<!--- TEST -->
210
211## An explicit job
212
213A [launch] coroutine builder returns a [Job] object that is a handle to the launched coroutine and can be
214used to explicitly wait for its completion. For example, you can wait for completion of the child coroutine
215and then print "Done" string:
216
217```kotlin
218import kotlinx.coroutines.*
219
220fun main() = runBlocking {
221//sampleStart
222    val job = launch { // launch a new coroutine and keep a reference to its Job
223        delay(1000L)
224        println("World!")
225    }
226    println("Hello")
227    job.join() // wait until child coroutine completes
228    println("Done")
229//sampleEnd
230}
231```
232{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
233
234> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-05.kt).
235>
236{type="note"}
237
238This code produces:
239
240```text
241Hello
242World!
243Done
244```
245
246<!--- TEST -->
247
248## Coroutines are light-weight
249
250Coroutines are less resource-intensive than JVM threads. Code that exhausts the
251JVM's available memory when using threads can be expressed using coroutines
252without hitting resource limits. For example, the following code launches
25350,000 distinct coroutines that each waits 5 seconds and then prints a period
254('.') while consuming very little memory:
255
256```kotlin
257import kotlinx.coroutines.*
258
259fun main() = runBlocking {
260    repeat(50_000) { // launch a lot of coroutines
261        launch {
262            delay(5000L)
263            print(".")
264        }
265    }
266}
267```
268{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
269
270> You can get the full code [here](../../kotlinx-coroutines-core/jvm/test/guide/example-basic-06.kt).
271>
272{type="note"}
273
274<!--- TEST lines.size == 1 && lines[0] == ".".repeat(50_000) -->
275
276If you write the same program using threads (remove `runBlocking`, replace
277`launch` with `thread`, and replace `delay` with `Thread.sleep`), it will
278consume a lot of memory. Depending on your operating system, JDK version,
279and its settings, it will either throw an out-of-memory error or start threads slowly
280so that there are never too many concurrently running threads.
281
282<!--- MODULE kotlinx-coroutines-core -->
283<!--- INDEX kotlinx.coroutines -->
284
285[launch]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
286[delay]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
287[runBlocking]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-blocking.html
288[CoroutineScope]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
289[_coroutineScope]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
290[Job]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/index.html
291
292<!--- END -->
293