SlideShare une entreprise Scribd logo
1  sur  145
Télécharger pour lire hors ligne
elizarov at JetBrains
Roman Elizarov
Introduction to Coroutines
Asynchronous
programming
How do we write code that waits
for something most of the time?
A toy problem
Kotlin fun requestToken(): Token {
// makes request for a token & waits
return token // returns result when received
}
1
fun requestToken(): Token { … }
fun createPost(token: Token, item: Item): Post {
// sends item to the server & waits
return post // returns resulting post
}
A toy problem
2
Kotlin
fun requestToken(): Token { … }
fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) {
// does some local processing of result
}
A toy problem
3
Kotlin
fun requestToken(): Token { … }
fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
A toy problem
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
1
2
3
Can be done with
threads!
Kotlin
fun requestToken(): Token {
// makes request for a token
// blocks the thread waiting for result
return token // returns result when received
}
fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
Threads
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Is anything wrong with it?
How many threads we can have?
100 🙂
How many threads we can have?
1000 😅
How many threads we can have?
10 000 😩
How many threads we can have?
100 000 😵
Callbacks to the rescue
Sort of …
Callbacks: before
fun requestToken(): Token {
// makes request for a token & waits
return token // returns result when received
}
1
Callbacks: after
fun requestTokenAsync(cb: (Token) -> Unit) {
// makes request for a token, invokes callback when done
// returns immediately
}
1
callback
Callbacks: before
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPost(token: Token, item: Item): Post {
// sends item to the server & waits
return post // returns resulting post
}
2
Callbacks: after
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) {
// sends item to the server, invokes callback when done
// returns immediately
}
2
callback
Callbacks: before
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Callbacks: after
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync { token ->
createPostAsync(token, item) { post ->
processPost(post)
}
}
}
aka “callback hell”
This is simplified. Handling
exceptions makes it a real mess
Futures/Promises/Rx
to the rescue
Sort of …
Futures: before
fun requestTokenAsync(cb: (Token) -> Unit) {
// makes request for a token, invokes callback when done
// returns immediately
}
1
Futures: after
fun requestTokenAsync(): Promise<Token> {
// makes request for a token
// returns promise for a future result immediately
}
1
future
Futures: before
fun requestTokenAsync(): Promise<Token> { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) {
// sends item to the server, invokes callback when done
// returns immediately
}
2
Futures: after
fun requestTokenAsync(): Promise<Token> { … }
fun createPostAsync(token: Token, item: Item): Promise<Post> {
// sends item to the server
// returns promise for a future result immediately
}
future
2
Futures: before
fun requestTokenAsync(): Promise<Token> { … }
fun createPostAsync(token: Token, item: Item): Promise<Post> …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync { token ->
createPostAsync(token, item) { post ->
processPost(post)
}
}
}
Futures: after
fun requestTokenAsync(): Promise<Token> { … }
fun createPostAsync(token: Token, item: Item): Promise<Post> …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
Composable &
propagates exceptions
No nesting indentation
Futures: after
fun requestTokenAsync(): Promise<Token> { … }
fun createPostAsync(token: Token, item: Item): Promise<Post> …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
But all those combinators…
Kotlin coroutines to the rescue
Let’s get real
Coroutines: before
fun requestTokenAsync(): Promise<Token> {
// makes request for a token
// returns promise for a future result immediately
}
1
Coroutines: after
suspend fun requestToken(): Token {
// makes request for a token & suspends
return token // returns result when received
}
1
Coroutines: after
suspend fun requestToken(): Token {
// makes request for a token & suspends
return token // returns result when received
}
1
natural signature
Coroutines: before
suspend fun requestToken(): Token { … }
fun createPostAsync(token: Token, item: Item): Promise<Post> {
// sends item to the server
// returns promise for a future result immediately
}
2
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post {
// sends item to the server & suspends
return post // returns result when received
}
2
Coroutines: before
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Like regular code
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
suspension
points
• Regular loops
Bonus features
for ((token, item) in list) {
createPost(token, item)
}
• Regular exception handing
Bonus features
try {
createPost(token, item)
} catch (e: BadTokenException) {
…
}
• Regular higher-order functions
• forEach, let, apply, repeat, filter, map, use, etc
Bonus features
file.readLines().forEach { line ->
createPost(token, line.toItem())
}
Everything like in blocking code
Suspending functions
Retrofit async
interface Service {
fun createPost(token: Token, item: Item): Call<Post>
}
Retrofit async
interface Service {
fun createPost(token: Token, item: Item): Call<Post>
}
future
Retrofit async
interface Service {
fun createPost(token: Token, item: Item): Call<Post>
}
suspend fun createPost(token: Token, item: Item): Post =
serviceInstance.createPost(token, item).await()
Retrofit async
interface Service {
fun createPost(token: Token, item: Item): Call<Post>
}
suspend fun createPost(token: Token, item: Item): Post =
serviceInstance.createPost(token, item).await()
natural signature
Retrofit async
interface Service {
fun createPost(token: Token, item: Item): Call<Post>
}
suspend fun createPost(token: Token, item: Item): Post =
serviceInstance.createPost(token, item).await()
Suspending extension function
from integration library
Composition
Beyond sequential
val post = createPost(token, item)
Higher-order functions
val post = retryIO {
createPost(token, item)
}
Higher-order functions
val post = retryIO { createPost(token, item) }
suspend fun <T> retryIO(block: suspend () -> T): T {
var curDelay = 1000L // start with 1 sec
while (true) {
try {
return block()
} catch (e: IOException) {
e.printStackTrace() // log the error
}
delay(curDelay)
curDelay = (curDelay * 2).coerceAtMost(60000L)
}
}
Higher-order functions
val post = retryIO { createPost(token, item) }
suspend fun <T> retryIO(block: suspend () -> T): T {
var curDelay = 1000L // start with 1 sec
while (true) {
try {
return block()
} catch (e: IOException) {
e.printStackTrace() // log the error
}
delay(curDelay)
curDelay = (curDelay * 2).coerceAtMost(60000L)
}
}
Higher-order functions
val post = retryIO { createPost(token, item) }
suspend fun <T> retryIO(block: suspend () -> T): T {
var curDelay = 1000L // start with 1 sec
while (true) {
try {
return block()
} catch (e: IOException) {
e.printStackTrace() // log the error
}
delay(curDelay)
curDelay = (curDelay * 2).coerceAtMost(60000L)
}
}
suspending lambda
Higher-order functions
val post = retryIO { createPost(token, item) }
suspend fun <T> retryIO(block: suspend () -> T): T {
var curDelay = 1000L // start with 1 sec
while (true) {
try {
return block()
} catch (e: IOException) {
e.printStackTrace() // log the error
}
delay(curDelay)
curDelay = (curDelay * 2).coerceAtMost(60000L)
}
}
Everything like in blocking code
Higher-order functions
val post = retryIO { createPost(token, item) }
suspend fun <T> retryIO(block: suspend () -> T): T {
var curDelay = 1000L // start with 1 sec
while (true) {
try {
return block()
} catch (e: IOException) {
e.printStackTrace() // log the error
}
delay(curDelay)
curDelay = (curDelay * 2).coerceAtMost(60000L)
}
}
Coroutine builders
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Error: Suspend function 'requestToken' should be called only from
a coroutine or another suspend function
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Can suspend execution
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Can suspend executionA regular function cannot
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Can suspend executionA regular function cannot
One cannot simply invoke
a suspending function
Launch
fun postItem(item: Item) {
launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
coroutine builder
fun postItem(item: Item) {
launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Fire and forget!
Returns immediately, coroutine
works in background thread pool
fun postItem(item: Item) {
launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
fun postItem(item: Item) {
launch(UI) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
UI Context
Just specify the context
fun postItem(item: Item) {
launch(UI) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
UI Context
And it gets executed on UI thread
Where’s the magic of launch?
fun launch(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> Unit
): Job { … }
A regular function
fun launch(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> Unit
): Job { … } suspending lambda
fun launch(
context: CoroutineContext = DefaultDispatcher,
block: suspend () -> Unit
): Job { … }
async / await
Kotlin-way
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Kotlin
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
async Task postItem(Item item) {
var token = await requestToken();
var post = await createPost(token, item);
processPost(post);
}
Classic-way
C# approach to the same problem
(also Python, TS, Dart, coming to JS)
C#
async Task<Token> requestToken() { … }
async Task<Post> createPost(Token token, Item item) { … }
void processPost(Post post) { … }
async Task postItem(Item item) {
var token = await requestToken();
var post = await createPost(token, item);
processPost(post);
}
Classic-way
mark with async
C#
async Task<Token> requestToken() { … }
async Task<Post> createPost(Token token, Item item) { … }
void processPost(Post post) { … }
async Task postItem(Item item) {
var token = await requestToken();
var post = await createPost(token, item);
processPost(post);
}
Classic-way
use await to suspend
C#
async Task<Token> requestToken() { … }
async Task<Post> createPost(Token token, Item item) { … }
void processPost(Post post) { … }
async Task postItem(Item item) {
var token = await requestToken();
var post = await createPost(token, item);
processPost(post);
}
Classic-way
C#
returns a future
async Task<Token> requestToken() { … }
async Task<Post> createPost(Token token, Item item) { … }
void processPost(Post post) { … }
Why no await keyword in Kotlin?
The problem with async
requestToken() VALID –> produces Task<Token>
await requestToken() VALID –> produces Token
concurrent behavior
sequential behavior
C#
C#
default
Kotlin suspending functions
are designed to imitate
sequential behavior
by default
Concurrency is hard
Concurrency has to be explicit
Kotlin approach to async
Concurrency where you need it
Use-case for async
async Task<Image> loadImageAsync(String name) { … }C#
Use-case for async
var promise1 = loadImageAsync(name1);
var promise2 = loadImageAsync(name2);
async Task<Image> loadImageAsync(String name) { … }
Start multiple operations
concurrently
C#
Use-case for async
var promise1 = loadImageAsync(name1);
var promise2 = loadImageAsync(name2);
var image1 = await promise1;
var image2 = await promise2;
async Task<Image> loadImageAsync(String name) { … }
and then wait for them
C#
Use-case for async
var result = combineImages(image1, image2);
C#
var promise1 = loadImageAsync(name1);
var promise2 = loadImageAsync(name2);
var image1 = await promise1;
var image2 = await promise2;
async Task<Image> loadImageAsync(String name) { … }
Kotlin async function
fun loadImageAsync(name: String): Deferred<Image> =
async { … }
Kotlin
Kotlin async function
fun loadImageAsync(name: String): Deferred<Image> =
async { … }
Kotlin
A regular function
Kotlin async function
fun loadImageAsync(name: String): Deferred<Image> =
async { … }
Kotlin’s future type
Kotlin
Kotlin async function
fun loadImageAsync(name: String): Deferred<Image> =
async { … }
async coroutine builder
Kotlin
Kotlin async function
fun loadImageAsync(name: String): Deferred<Image> =
async { … }
val deferred1 = loadImageAsync(name1)
val deferred2 = loadImageAsync(name2)
Start multiple operations
concurrently
Kotlin
Kotlin async function
fun loadImageAsync(name: String): Deferred<Image> =
async { … }
val deferred1 = loadImageAsync(name1)
val deferred2 = loadImageAsync(name2)
val image1 = deferred1.await()
val image2 = deferred2.await()
and then wait for them
await function
Suspends until deferred is complete
Kotlin
Kotlin async function
fun loadImageAsync(name: String): Deferred<Image> =
async { … }
val deferred1 = loadImageAsync(name1)
val deferred2 = loadImageAsync(name2)
val image1 = deferred1.await()
val image2 = deferred2.await()
val result = combineImages(image1, image2)
Kotlin
Using async function when needed
suspend fun loadImage(name: String): Image { … }
Is defined as suspending function, not async
Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
return combineImages(deferred1.await(), deferred2.await())
}
Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
return combineImages(deferred1.await(), deferred2.await())
}
Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
return combineImages(deferred1.await(), deferred2.await())
}
Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
return combineImages(deferred1.await(), deferred2.await())
}
Kotlin approach to async
requestToken() VALID –> produces Token
async { requestToken() } VALID –> produces Deferred<Token>
sequential behavior
concurrent behavior
Kotlin
Kotlin
default
Coroutines
What are coroutines
conceptually?
What are coroutines
conceptually?
Coroutines are like very light-weight threads
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
This coroutine builder runs coroutine
in the context of invoker thread
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
Suspends for 1 second
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
We can join a job
just like a thread
Demo
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
Try that with 100k threads!
Prints 100k dots after one second delay
fun main(args: Array<String>) = runBlocking<Unit> {
val jobs = List(100_000) {
launch {
delay(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
fun main(args: Array<String>) {
val jobs = List(100_000) {
thread {
Thread.sleep(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
Demo
fun main(args: Array<String>) {
val jobs = List(100_000) {
thread {
Thread.sleep(1000L)
print(".")
}
}
jobs.forEach { it.join() }
}
Example
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
Java interop
CompletableFuture<Image> loadImageAsync(String name) { … }Java
CompletableFuture<Image> loadImageAsync(String name) { … }
CompletableFuture<Image> loadAndCombineAsync(String name1,
String name2)
Imagine implementing it in Java…
Java
CompletableFuture<Image> loadImageAsync(String name) { … }
CompletableFuture<Image> loadAndCombineAsync(String name1,
String name2)
{
CompletableFuture<Image> future1 = loadImageAsync(name1);
CompletableFuture<Image> future2 = loadImageAsync(name2);
return future1.thenCompose(image1 ->
future2.thenCompose(image2 ->
CompletableFuture.supplyAsync(() ->
combineImages(image1, image2))));
}
Java
CompletableFuture<Image> loadImageAsync(String name) { … }
CompletableFuture<Image> loadAndCombineAsync(String name1,
String name2)
{
CompletableFuture<Image> future1 = loadImageAsync(name1);
CompletableFuture<Image> future2 = loadImageAsync(name2);
return future1.thenCompose(image1 ->
future2.thenCompose(image2 ->
CompletableFuture.supplyAsync(() ->
combineImages(image1, image2))));
}
Java
CompletableFuture<Image> loadImageAsync(String name) { … }
fun loadAndCombineAsync(
name1: String,
name2: String
): CompletableFuture<Image> =
future {
val future1 = loadImageAsync(name1)
val future2 = loadImageAsync(name2)
combineImages(future1.await(), future2.await())
}
Kotlin
Java
CompletableFuture<Image> loadImageAsync(String name) { … }
fun loadAndCombineAsync(
name1: String,
name2: String
): CompletableFuture<Image> =
future {
val future1 = loadImageAsync(name1)
val future2 = loadImageAsync(name2)
combineImages(future1.await(), future2.await())
}
Kotlin
Java
CompletableFuture<Image> loadImageAsync(String name) { … }
fun loadAndCombineAsync(
name1: String,
name2: String
): CompletableFuture<Image> =
future {
val future1 = loadImageAsync(name1)
val future2 = loadImageAsync(name2)
combineImages(future1.await(), future2.await())
}
future coroutine builder
Kotlin
Java
CompletableFuture<Image> loadImageAsync(String name) { … }
fun loadAndCombineAsync(
name1: String,
name2: String
): CompletableFuture<Image> =
future {
val future1 = loadImageAsync(name1)
val future2 = loadImageAsync(name2)
combineImages(future1.await(), future2.await())
}
Kotlin
Java
CompletableFuture<Image> loadImageAsync(String name) { … }
fun loadAndCombineAsync(
name1: String,
name2: String
): CompletableFuture<Image> =
future {
val future1 = loadImageAsync(name1)
val future2 = loadImageAsync(name2)
combineImages(future1.await(), future2.await())
}
Extension for Java’s CompletableFuture
Kotlin
Java
Beyond
asynchronous code
Fibonacci sequence
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
A coroutine builder with
restricted suspension
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
A suspending function
The same building blocks
fun <T> buildSequence(
builderAction: suspend SequenceBuilder<T>.() -> Unit
): Sequence<T> { … }
fun <T> buildSequence(
builderAction: suspend SequenceBuilder<T>.() -> Unit
): Sequence<T> { … }
Result is a synchronous sequence
fun <T> buildSequence(
builderAction: suspend SequenceBuilder<T>.() -> Unit
): Sequence<T> { … }
Suspending lambda with receiver
fun <T> buildSequence(
builderAction: suspend SequenceBuilder<T>.() -> Unit
): Sequence<T> { … }
@RestrictsSuspension
abstract class SequenceBuilder<in T> {
abstract suspend fun yield(value: T)
}
Coroutine is restricted only to
suspending functions defined here
Synchronous
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next())
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next())
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next())
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next())
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next()) // 1
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next()) // 1
println(iter.next()) // 2
val fibonacci = buildSequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next()) // 1
println(iter.next()) // 2
Synchronous with invoker
Library vs Language
Classic async
async/await
generate/yield
Keywords
Kotlin coroutines
suspend Modifier
Kotlin coroutines
Standard
library
Kotlin coroutines
Standard
library
kotlinx-coroutines
launch, async,
runBlocking, future, delay,
Job, Deferred, etc
http://github.com/kotlin/kotlinx.coroutines
Experimental status
Coroutines are here to stay
Backwards compatible inside 1.1 & 1.2
To be finalized in the future
#kotlinconf17
relizarov
elizarov at JetBrains
Roman Elizarov
Thank you
Any questions?

Contenu connexe

Tendances

Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented ProgrammingScott Wlaschin
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKirill Rozov
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Scott Wlaschin
 
A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...
A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...
A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...ufpb
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous JavascriptGarrett Welson
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Scott Wlaschin
 
Asynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFutureAsynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFutureJosé Paumard
 
PHP unserialization vulnerabilities: What are we missing?
PHP unserialization vulnerabilities: What are we missing?PHP unserialization vulnerabilities: What are we missing?
PHP unserialization vulnerabilities: What are we missing?Sam Thomas
 
Mockito a simple, intuitive mocking framework
Mockito   a simple, intuitive mocking frameworkMockito   a simple, intuitive mocking framework
Mockito a simple, intuitive mocking frameworkPhat VU
 
Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4ICS
 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!Brendan Eich
 
KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기
KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기
KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기흥배 최
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)Scott Wlaschin
 
In the DOM, no one will hear you scream
In the DOM, no one will hear you screamIn the DOM, no one will hear you scream
In the DOM, no one will hear you screamMario Heiderich
 

Tendances (20)

Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Kotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is comingKotlin Coroutines. Flow is coming
Kotlin Coroutines. Flow is coming
 
Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)Functional Design Patterns (DevTernity 2018)
Functional Design Patterns (DevTernity 2018)
 
A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...
A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...
A little bit about code injection in WebApplication Frameworks (CVE-2018-1466...
 
Intro to Asynchronous Javascript
Intro to Asynchronous JavascriptIntro to Asynchronous Javascript
Intro to Asynchronous Javascript
 
Fetch API Talk
Fetch API TalkFetch API Talk
Fetch API Talk
 
Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)Functional Programming Patterns (NDC London 2014)
Functional Programming Patterns (NDC London 2014)
 
Epoxy 介紹
Epoxy 介紹Epoxy 介紹
Epoxy 介紹
 
Asynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFutureAsynchronous API in Java8, how to use CompletableFuture
Asynchronous API in Java8, how to use CompletableFuture
 
PHP unserialization vulnerabilities: What are we missing?
PHP unserialization vulnerabilities: What are we missing?PHP unserialization vulnerabilities: What are we missing?
PHP unserialization vulnerabilities: What are we missing?
 
JUnit 4
JUnit 4JUnit 4
JUnit 4
 
Rust
RustRust
Rust
 
Mockito a simple, intuitive mocking framework
Mockito   a simple, intuitive mocking frameworkMockito   a simple, intuitive mocking framework
Mockito a simple, intuitive mocking framework
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4Best Practices in Qt Quick/QML - Part 1 of 4
Best Practices in Qt Quick/QML - Part 1 of 4
 
Rxjs ngvikings
Rxjs ngvikingsRxjs ngvikings
Rxjs ngvikings
 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!
 
KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기
KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기
KGC 2016 오픈소스 네트워크 엔진 Super socket 사용하기
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
In the DOM, no one will hear you scream
In the DOM, no one will hear you screamIn the DOM, no one will hear you scream
In the DOM, no one will hear you scream
 

Similaire à Introduction to Coroutines @ KotlinConf 2017

Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Roman Elizarov
 
Fresh Async with Kotlin
Fresh Async with KotlinFresh Async with Kotlin
Fresh Async with KotlinC4Media
 
Dive into kotlins coroutines
Dive into kotlins coroutinesDive into kotlins coroutines
Dive into kotlins coroutinesFreddie Wang
 
Kotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenesKotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenesAnh Vu
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드NAVER Engineering
 
Coroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth reviewCoroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth reviewDmytro Zaitsev
 
Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.UA Mobile
 
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando CoroutinesTDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutinestdc-globalcode
 
Programação assíncrona utilizando Coroutines
Programação assíncrona utilizando CoroutinesProgramação assíncrona utilizando Coroutines
Programação assíncrona utilizando CoroutinesDiego Gonçalves Santos
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresiMasters
 
Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Artur Latoszewski
 
Kotlin의 코루틴은 어떻게 동작하는가
Kotlin의 코루틴은 어떻게 동작하는가Kotlin의 코루틴은 어떻게 동작하는가
Kotlin의 코루틴은 어떻게 동작하는가Chang W. Doh
 
Kotlin - Coroutine
Kotlin - CoroutineKotlin - Coroutine
Kotlin - CoroutineSean Tsai
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Waytdc-globalcode
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴명신 김
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and InferenceRichard Fox
 

Similaire à Introduction to Coroutines @ KotlinConf 2017 (20)

Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017Fresh Async with Kotlin @ QConSF 2017
Fresh Async with Kotlin @ QConSF 2017
 
Fresh Async with Kotlin
Fresh Async with KotlinFresh Async with Kotlin
Fresh Async with Kotlin
 
Dive into kotlins coroutines
Dive into kotlins coroutinesDive into kotlins coroutines
Dive into kotlins coroutines
 
Kotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenesKotlin coroutine - behind the scenes
Kotlin coroutine - behind the scenes
 
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
200819 NAVER TECH CONCERT 03_화려한 코루틴이 내 앱을 감싸네! 코루틴으로 작성해보는 깔끔한 비동기 코드
 
Coroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth reviewCoroutines in Kotlin. In-depth review
Coroutines in Kotlin. In-depth review
 
Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.
 
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando CoroutinesTDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
 
Programação assíncrona utilizando Coroutines
Programação assíncrona utilizando CoroutinesProgramação assíncrona utilizando Coroutines
Programação assíncrona utilizando Coroutines
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
 
Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?Kotlin coroutine - the next step for RxJava developer?
Kotlin coroutine - the next step for RxJava developer?
 
Kotlin의 코루틴은 어떻게 동작하는가
Kotlin의 코루틴은 어떻게 동작하는가Kotlin의 코루틴은 어떻게 동작하는가
Kotlin의 코루틴은 어떻게 동작하는가
 
Current State of Coroutines
Current State of CoroutinesCurrent State of Coroutines
Current State of Coroutines
 
Kotlin - Coroutine
Kotlin - CoroutineKotlin - Coroutine
Kotlin - Coroutine
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
 
Kotlin Coroutines - the new async
Kotlin Coroutines - the new asyncKotlin Coroutines - the new async
Kotlin Coroutines - the new async
 
Coroutines in Kotlin
Coroutines in KotlinCoroutines in Kotlin
Coroutines in Kotlin
 
C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴C#을 이용한 task 병렬화와 비동기 패턴
C#을 이용한 task 병렬화와 비동기 패턴
 
Generics and Inference
Generics and InferenceGenerics and Inference
Generics and Inference
 
FSE 2008
FSE 2008FSE 2008
FSE 2008
 

Plus de Roman Elizarov

Scale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOneScale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOneRoman Elizarov
 
Lock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesLock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesRoman Elizarov
 
Non blocking programming and waiting
Non blocking programming and waitingNon blocking programming and waiting
Non blocking programming and waitingRoman Elizarov
 
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
Многопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и ПрактикаМногопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и ПрактикаRoman Elizarov
 
Wait for your fortune without Blocking!
Wait for your fortune without Blocking!Wait for your fortune without Blocking!
Wait for your fortune without Blocking!Roman Elizarov
 
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
Why GC is eating all my CPU?
Why GC is eating all my CPU?Why GC is eating all my CPU?
Why GC is eating all my CPU?Roman Elizarov
 
Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)Roman Elizarov
 
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)Roman Elizarov
 
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
Java Serialization Facts and Fallacies
Java Serialization Facts and FallaciesJava Serialization Facts and Fallacies
Java Serialization Facts and FallaciesRoman Elizarov
 
Millions quotes per second in pure java
Millions quotes per second in pure javaMillions quotes per second in pure java
Millions quotes per second in pure javaRoman Elizarov
 
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems ReviewRoman Elizarov
 
The theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmerThe theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmerRoman Elizarov
 
Пишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данныхПишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данныхRoman Elizarov
 

Plus de Roman Elizarov (18)

Scale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOneScale Up with Lock-Free Algorithms @ JavaOne
Scale Up with Lock-Free Algorithms @ JavaOne
 
Lock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin CoroutinesLock-free algorithms for Kotlin Coroutines
Lock-free algorithms for Kotlin Coroutines
 
Non blocking programming and waiting
Non blocking programming and waitingNon blocking programming and waiting
Non blocking programming and waiting
 
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
 
Многопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и ПрактикаМногопоточное Программирование - Теория и Практика
Многопоточное Программирование - Теория и Практика
 
Wait for your fortune without Blocking!
Wait for your fortune without Blocking!Wait for your fortune without Blocking!
Wait for your fortune without Blocking!
 
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
 
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
 
Why GC is eating all my CPU?
Why GC is eating all my CPU?Why GC is eating all my CPU?
Why GC is eating all my CPU?
 
Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)
 
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
 
DIY Java Profiling
DIY Java ProfilingDIY Java Profiling
DIY Java Profiling
 
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
 
Java Serialization Facts and Fallacies
Java Serialization Facts and FallaciesJava Serialization Facts and Fallacies
Java Serialization Facts and Fallacies
 
Millions quotes per second in pure java
Millions quotes per second in pure javaMillions quotes per second in pure java
Millions quotes per second in pure java
 
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems ReviewACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
 
The theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmerThe theory of concurrent programming for a seasoned programmer
The theory of concurrent programming for a seasoned programmer
 
Пишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данныхПишем самый быстрый хеш для кэширования данных
Пишем самый быстрый хеш для кэширования данных
 

Dernier

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 

Dernier (20)

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 

Introduction to Coroutines @ KotlinConf 2017

  • 1. elizarov at JetBrains Roman Elizarov Introduction to Coroutines
  • 3. How do we write code that waits for something most of the time?
  • 4. A toy problem Kotlin fun requestToken(): Token { // makes request for a token & waits return token // returns result when received } 1
  • 5. fun requestToken(): Token { … } fun createPost(token: Token, item: Item): Post { // sends item to the server & waits return post // returns resulting post } A toy problem 2 Kotlin
  • 6. fun requestToken(): Token { … } fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { // does some local processing of result } A toy problem 3 Kotlin
  • 7. fun requestToken(): Token { … } fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } A toy problem fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } 1 2 3 Can be done with threads! Kotlin
  • 8. fun requestToken(): Token { // makes request for a token // blocks the thread waiting for result return token // returns result when received } fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } Threads fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Is anything wrong with it?
  • 9. How many threads we can have? 100 🙂
  • 10. How many threads we can have? 1000 😅
  • 11. How many threads we can have? 10 000 😩
  • 12. How many threads we can have? 100 000 😵
  • 13. Callbacks to the rescue Sort of …
  • 14. Callbacks: before fun requestToken(): Token { // makes request for a token & waits return token // returns result when received } 1
  • 15. Callbacks: after fun requestTokenAsync(cb: (Token) -> Unit) { // makes request for a token, invokes callback when done // returns immediately } 1 callback
  • 16. Callbacks: before fun requestTokenAsync(cb: (Token) -> Unit) { … } fun createPost(token: Token, item: Item): Post { // sends item to the server & waits return post // returns resulting post } 2
  • 17. Callbacks: after fun requestTokenAsync(cb: (Token) -> Unit) { … } fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) { // sends item to the server, invokes callback when done // returns immediately } 2 callback
  • 18. Callbacks: before fun requestTokenAsync(cb: (Token) -> Unit) { … } fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 19. Callbacks: after fun requestTokenAsync(cb: (Token) -> Unit) { … } fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) { … } fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync { token -> createPostAsync(token, item) { post -> processPost(post) } } } aka “callback hell” This is simplified. Handling exceptions makes it a real mess
  • 21. Futures: before fun requestTokenAsync(cb: (Token) -> Unit) { // makes request for a token, invokes callback when done // returns immediately } 1
  • 22. Futures: after fun requestTokenAsync(): Promise<Token> { // makes request for a token // returns promise for a future result immediately } 1 future
  • 23. Futures: before fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) { // sends item to the server, invokes callback when done // returns immediately } 2
  • 24. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token: Token, item: Item): Promise<Post> { // sends item to the server // returns promise for a future result immediately } future 2
  • 25. Futures: before fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token: Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync { token -> createPostAsync(token, item) { post -> processPost(post) } } }
  • 26. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token: Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } } Composable & propagates exceptions No nesting indentation
  • 27. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token: Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } } But all those combinators…
  • 28. Kotlin coroutines to the rescue Let’s get real
  • 29. Coroutines: before fun requestTokenAsync(): Promise<Token> { // makes request for a token // returns promise for a future result immediately } 1
  • 30. Coroutines: after suspend fun requestToken(): Token { // makes request for a token & suspends return token // returns result when received } 1
  • 31. Coroutines: after suspend fun requestToken(): Token { // makes request for a token & suspends return token // returns result when received } 1 natural signature
  • 32. Coroutines: before suspend fun requestToken(): Token { … } fun createPostAsync(token: Token, item: Item): Promise<Post> { // sends item to the server // returns promise for a future result immediately } 2
  • 33. Coroutines: after suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { // sends item to the server & suspends return post // returns result when received } 2
  • 34. Coroutines: before suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } }
  • 35. Coroutines: after suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 36. Coroutines: after suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Like regular code
  • 37. Coroutines: after suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } suspension points
  • 38. • Regular loops Bonus features for ((token, item) in list) { createPost(token, item) }
  • 39. • Regular exception handing Bonus features try { createPost(token, item) } catch (e: BadTokenException) { … }
  • 40. • Regular higher-order functions • forEach, let, apply, repeat, filter, map, use, etc Bonus features file.readLines().forEach { line -> createPost(token, line.toItem()) } Everything like in blocking code
  • 42. Retrofit async interface Service { fun createPost(token: Token, item: Item): Call<Post> }
  • 43. Retrofit async interface Service { fun createPost(token: Token, item: Item): Call<Post> } future
  • 44. Retrofit async interface Service { fun createPost(token: Token, item: Item): Call<Post> } suspend fun createPost(token: Token, item: Item): Post = serviceInstance.createPost(token, item).await()
  • 45. Retrofit async interface Service { fun createPost(token: Token, item: Item): Call<Post> } suspend fun createPost(token: Token, item: Item): Post = serviceInstance.createPost(token, item).await() natural signature
  • 46. Retrofit async interface Service { fun createPost(token: Token, item: Item): Call<Post> } suspend fun createPost(token: Token, item: Item): Post = serviceInstance.createPost(token, item).await() Suspending extension function from integration library
  • 48. val post = createPost(token, item)
  • 49. Higher-order functions val post = retryIO { createPost(token, item) }
  • 50. Higher-order functions val post = retryIO { createPost(token, item) } suspend fun <T> retryIO(block: suspend () -> T): T { var curDelay = 1000L // start with 1 sec while (true) { try { return block() } catch (e: IOException) { e.printStackTrace() // log the error } delay(curDelay) curDelay = (curDelay * 2).coerceAtMost(60000L) } }
  • 51. Higher-order functions val post = retryIO { createPost(token, item) } suspend fun <T> retryIO(block: suspend () -> T): T { var curDelay = 1000L // start with 1 sec while (true) { try { return block() } catch (e: IOException) { e.printStackTrace() // log the error } delay(curDelay) curDelay = (curDelay * 2).coerceAtMost(60000L) } }
  • 52. Higher-order functions val post = retryIO { createPost(token, item) } suspend fun <T> retryIO(block: suspend () -> T): T { var curDelay = 1000L // start with 1 sec while (true) { try { return block() } catch (e: IOException) { e.printStackTrace() // log the error } delay(curDelay) curDelay = (curDelay * 2).coerceAtMost(60000L) } } suspending lambda
  • 53. Higher-order functions val post = retryIO { createPost(token, item) } suspend fun <T> retryIO(block: suspend () -> T): T { var curDelay = 1000L // start with 1 sec while (true) { try { return block() } catch (e: IOException) { e.printStackTrace() // log the error } delay(curDelay) curDelay = (curDelay * 2).coerceAtMost(60000L) } } Everything like in blocking code
  • 54. Higher-order functions val post = retryIO { createPost(token, item) } suspend fun <T> retryIO(block: suspend () -> T): T { var curDelay = 1000L // start with 1 sec while (true) { try { return block() } catch (e: IOException) { e.printStackTrace() // log the error } delay(curDelay) curDelay = (curDelay * 2).coerceAtMost(60000L) } }
  • 56. Coroutines revisited suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 57. Coroutines revisited suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  • 58. Coroutines revisited suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Error: Suspend function 'requestToken' should be called only from a coroutine or another suspend function
  • 59. Coroutines revisited suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Can suspend execution
  • 60. Coroutines revisited suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Can suspend executionA regular function cannot
  • 61. Coroutines revisited suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Can suspend executionA regular function cannot One cannot simply invoke a suspending function
  • 62. Launch fun postItem(item: Item) { launch { val token = requestToken() val post = createPost(token, item) processPost(post) } } coroutine builder
  • 63. fun postItem(item: Item) { launch { val token = requestToken() val post = createPost(token, item) processPost(post) } } Fire and forget! Returns immediately, coroutine works in background thread pool
  • 64. fun postItem(item: Item) { launch { val token = requestToken() val post = createPost(token, item) processPost(post) } }
  • 65. fun postItem(item: Item) { launch(UI) { val token = requestToken() val post = createPost(token, item) processPost(post) } } UI Context Just specify the context
  • 66. fun postItem(item: Item) { launch(UI) { val token = requestToken() val post = createPost(token, item) processPost(post) } } UI Context And it gets executed on UI thread
  • 67. Where’s the magic of launch?
  • 68. fun launch( context: CoroutineContext = DefaultDispatcher, block: suspend () -> Unit ): Job { … } A regular function
  • 69. fun launch( context: CoroutineContext = DefaultDispatcher, block: suspend () -> Unit ): Job { … } suspending lambda
  • 70. fun launch( context: CoroutineContext = DefaultDispatcher, block: suspend () -> Unit ): Job { … }
  • 72. Kotlin-way suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Kotlin suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … }
  • 73. async Task postItem(Item item) { var token = await requestToken(); var post = await createPost(token, item); processPost(post); } Classic-way C# approach to the same problem (also Python, TS, Dart, coming to JS) C# async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  • 74. async Task postItem(Item item) { var token = await requestToken(); var post = await createPost(token, item); processPost(post); } Classic-way mark with async C# async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  • 75. async Task postItem(Item item) { var token = await requestToken(); var post = await createPost(token, item); processPost(post); } Classic-way use await to suspend C# async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  • 76. async Task postItem(Item item) { var token = await requestToken(); var post = await createPost(token, item); processPost(post); } Classic-way C# returns a future async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  • 77. Why no await keyword in Kotlin? The problem with async requestToken() VALID –> produces Task<Token> await requestToken() VALID –> produces Token concurrent behavior sequential behavior C# C# default
  • 78. Kotlin suspending functions are designed to imitate sequential behavior by default Concurrency is hard Concurrency has to be explicit
  • 79. Kotlin approach to async Concurrency where you need it
  • 80. Use-case for async async Task<Image> loadImageAsync(String name) { … }C#
  • 81. Use-case for async var promise1 = loadImageAsync(name1); var promise2 = loadImageAsync(name2); async Task<Image> loadImageAsync(String name) { … } Start multiple operations concurrently C#
  • 82. Use-case for async var promise1 = loadImageAsync(name1); var promise2 = loadImageAsync(name2); var image1 = await promise1; var image2 = await promise2; async Task<Image> loadImageAsync(String name) { … } and then wait for them C#
  • 83. Use-case for async var result = combineImages(image1, image2); C# var promise1 = loadImageAsync(name1); var promise2 = loadImageAsync(name2); var image1 = await promise1; var image2 = await promise2; async Task<Image> loadImageAsync(String name) { … }
  • 84. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = async { … } Kotlin
  • 85. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = async { … } Kotlin A regular function
  • 86. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = async { … } Kotlin’s future type Kotlin
  • 87. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = async { … } async coroutine builder Kotlin
  • 88. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = async { … } val deferred1 = loadImageAsync(name1) val deferred2 = loadImageAsync(name2) Start multiple operations concurrently Kotlin
  • 89. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = async { … } val deferred1 = loadImageAsync(name1) val deferred2 = loadImageAsync(name2) val image1 = deferred1.await() val image2 = deferred2.await() and then wait for them await function Suspends until deferred is complete Kotlin
  • 90. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = async { … } val deferred1 = loadImageAsync(name1) val deferred2 = loadImageAsync(name2) val image1 = deferred1.await() val image2 = deferred2.await() val result = combineImages(image1, image2) Kotlin
  • 91. Using async function when needed suspend fun loadImage(name: String): Image { … } Is defined as suspending function, not async
  • 92. Using async function when needed suspend fun loadImage(name: String): Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } return combineImages(deferred1.await(), deferred2.await()) }
  • 93. Using async function when needed suspend fun loadImage(name: String): Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } return combineImages(deferred1.await(), deferred2.await()) }
  • 94. Using async function when needed suspend fun loadImage(name: String): Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } return combineImages(deferred1.await(), deferred2.await()) }
  • 95. Using async function when needed suspend fun loadImage(name: String): Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } return combineImages(deferred1.await(), deferred2.await()) }
  • 96. Kotlin approach to async requestToken() VALID –> produces Token async { requestToken() } VALID –> produces Deferred<Token> sequential behavior concurrent behavior Kotlin Kotlin default
  • 99. What are coroutines conceptually? Coroutines are like very light-weight threads
  • 100. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example
  • 101. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example This coroutine builder runs coroutine in the context of invoker thread
  • 102. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example
  • 103. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example
  • 104. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example Suspends for 1 second
  • 105. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example We can join a job just like a thread
  • 106. Demo
  • 107. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example Try that with 100k threads! Prints 100k dots after one second delay
  • 108. fun main(args: Array<String>) = runBlocking<Unit> { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } Example
  • 109. fun main(args: Array<String>) { val jobs = List(100_000) { thread { Thread.sleep(1000L) print(".") } } jobs.forEach { it.join() } } Example
  • 110. Demo
  • 111. fun main(args: Array<String>) { val jobs = List(100_000) { thread { Thread.sleep(1000L) print(".") } } jobs.forEach { it.join() } } Example Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
  • 114. CompletableFuture<Image> loadImageAsync(String name) { … } CompletableFuture<Image> loadAndCombineAsync(String name1, String name2) Imagine implementing it in Java… Java
  • 115. CompletableFuture<Image> loadImageAsync(String name) { … } CompletableFuture<Image> loadAndCombineAsync(String name1, String name2) { CompletableFuture<Image> future1 = loadImageAsync(name1); CompletableFuture<Image> future2 = loadImageAsync(name2); return future1.thenCompose(image1 -> future2.thenCompose(image2 -> CompletableFuture.supplyAsync(() -> combineImages(image1, image2)))); } Java
  • 116. CompletableFuture<Image> loadImageAsync(String name) { … } CompletableFuture<Image> loadAndCombineAsync(String name1, String name2) { CompletableFuture<Image> future1 = loadImageAsync(name1); CompletableFuture<Image> future2 = loadImageAsync(name2); return future1.thenCompose(image1 -> future2.thenCompose(image2 -> CompletableFuture.supplyAsync(() -> combineImages(image1, image2)))); } Java
  • 117. CompletableFuture<Image> loadImageAsync(String name) { … } fun loadAndCombineAsync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadImageAsync(name1) val future2 = loadImageAsync(name2) combineImages(future1.await(), future2.await()) } Kotlin Java
  • 118. CompletableFuture<Image> loadImageAsync(String name) { … } fun loadAndCombineAsync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadImageAsync(name1) val future2 = loadImageAsync(name2) combineImages(future1.await(), future2.await()) } Kotlin Java
  • 119. CompletableFuture<Image> loadImageAsync(String name) { … } fun loadAndCombineAsync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadImageAsync(name1) val future2 = loadImageAsync(name2) combineImages(future1.await(), future2.await()) } future coroutine builder Kotlin Java
  • 120. CompletableFuture<Image> loadImageAsync(String name) { … } fun loadAndCombineAsync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadImageAsync(name1) val future2 = loadImageAsync(name2) combineImages(future1.await(), future2.await()) } Kotlin Java
  • 121. CompletableFuture<Image> loadImageAsync(String name) { … } fun loadAndCombineAsync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadImageAsync(name1) val future2 = loadImageAsync(name2) combineImages(future1.await(), future2.await()) } Extension for Java’s CompletableFuture Kotlin Java
  • 123. Fibonacci sequence val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } }
  • 124. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } A coroutine builder with restricted suspension
  • 125. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } A suspending function
  • 126. The same building blocks fun <T> buildSequence( builderAction: suspend SequenceBuilder<T>.() -> Unit ): Sequence<T> { … }
  • 127. fun <T> buildSequence( builderAction: suspend SequenceBuilder<T>.() -> Unit ): Sequence<T> { … } Result is a synchronous sequence
  • 128. fun <T> buildSequence( builderAction: suspend SequenceBuilder<T>.() -> Unit ): Sequence<T> { … } Suspending lambda with receiver
  • 129. fun <T> buildSequence( builderAction: suspend SequenceBuilder<T>.() -> Unit ): Sequence<T> { … } @RestrictsSuspension abstract class SequenceBuilder<in T> { abstract suspend fun yield(value: T) } Coroutine is restricted only to suspending functions defined here
  • 130. Synchronous val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator()
  • 131. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next())
  • 132. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next())
  • 133. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1
  • 134. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next())
  • 135. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next())
  • 136. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next()) // 1
  • 137. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next()) // 1 println(iter.next()) // 2
  • 138. val fibonacci = buildSequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next()) // 1 println(iter.next()) // 2 Synchronous with invoker
  • 143. Kotlin coroutines Standard library kotlinx-coroutines launch, async, runBlocking, future, delay, Job, Deferred, etc http://github.com/kotlin/kotlinx.coroutines
  • 144. Experimental status Coroutines are here to stay Backwards compatible inside 1.1 & 1.2 To be finalized in the future
  • 145. #kotlinconf17 relizarov elizarov at JetBrains Roman Elizarov Thank you Any questions?