Introduction to Coroutines. Roman Elizarov elizarov at JetBrains

Similar documents
Fresh Async With Kotlin. Presented at QCon SF, 2017 /Roman JetBrains

Deep dive into Coroutines on JVM. Roman Elizarov elizarov at JetBrains

JS Event Loop, Promises, Async Await etc. Slava Kim

Asynchronous Functions in C#

Asynchronous I/O: A Case Study in Python

An Introduction to TypeScript. Personal Info

Architecture using Functional Programming concepts < + >

in Microservices using DDD, Event Sourcing & CQRS Augusto Branquinho Mike Shigueru Matsumoto

An Async Primer. By Bill Wagner August Introduction

Asynchronous JS. SWE 432, Fall Web Application Development

ECMAScript 2015 and beyond The Future of JavaScript is Now!

Lock-free algorithms for Kotlin coroutines. It is all about scalability Presented at SPTCC 2017 /Roman JetBrains

The Various Faces of the.net Task Parallel Library

Getting Started with Kotlin. Commerzbank Java Developer Day

Scale Up with Lock-Free Algorithms. Non-blocking concurrency on JVM Presented at JavaOne 2017 /Roman JetBrains

Asynchronous Programming Demystified

Parallel Code Smells: A Top 10 List

CPL 2016, week 6. Asynchronous execution. Oleg Batrashev. March 14, Institute of Computer Science, Tartu, Estonia

Overview of Advanced Java 8 CompletableFuture Features (Part 2)

2 years without Java or reload Android development with Kotlin.

INF 102 CONCEPTS OF PROG. LANGS FUNCTIONAL COMPOSITION. Instructors: James Jones Copyright Instructors.

Pace University. Fundamental Concepts of CS121 1

Asynchronous OSGi: Promises for the masses. Tim Ward.

Futures. Prof. Clarkson Fall Today s music: It's Gonna be Me by *NSYNC

Paradigmas de Computação Paralela

Concurrent Programming in C++ Venkat

Asynchronous Programming - Done right

POINT OF FAILURES TOPICS .NET. msdn

This paper explains in more detail some of the proposed simplifications from P1342R0.

DON'T BLOCK YOUR MOBILES AND INTERNET OF THINGS

C# Asynchronous Programming Model

Writing Browser Extensions in Kotlin. Kirill Rakhman busradar.com

ECMAScript 2015 The Future of JavaScript is Now!

Manoj Kumar- From Call back's hell to using Async Await: Automated testing with JavaScript

INF 212 ANALYSIS OF PROG. LANGS FUNCTION COMPOSITION. Instructors: Crista Lopes Copyright Instructors.

Kotlin for the Pragmatic Functionalist

Developing BPEL processes. Third part: advanced BPEL concepts and examples

Don't Call Us, We'll Call You:

C# Programming in the.net Framework

Overview of Advanced Java 8 CompletableFuture Features (Part 3)

VS08 This One Goes to Going Parallel with PFX, PLINQ, TPL and Async Keywords

Practical Concurrency. Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited.

A Long Time Ago 2 / 64

ASYNCHRONOUS PROGRAMMING IN C# 5 WITHOUT USE OF MULTIPLE THREADS

Python Asynchronous Programming with Salt Stack (tornado, asyncio) and RxPY

Concurrency Analysis of Asynchronous APIs

HPX The C++ Standards Library for Concurrency and Parallelism. Hartmut Kaiser

Concurrency COMS W4115. Prof. Stephen A. Edwards Spring 2002 Columbia University Department of Computer Science

Programming C# 5.0. Ian Griffiths O'REILLY' Beijing Cambridge * Farnham Kbln Sebastopol Tokyo

Implementing Coroutines. Faking Coroutines in Java

MCSA Universal Windows Platform. A Success Guide to Prepare- Programming in C# edusum.com

Simplifying Asynchronous Code with

Advanced Flow of Control -- Introduction

Comet and WebSocket Web Applications How to Scale Server-Side Event-Driven Scenarios

Compose Chaos. Part 1: RAII Applied to Concurrency <image of chaos in a lego piece shape>

Java Threads. COMP 585 Noteset #2 1

Produced by. Design Patterns. MSc in Computer Science. Eamonn de Leastar

Better Code: Concurrency Sean Parent Principal Scientist Adobe Systems Incorporated. All Rights Reserved.

Chapter 17: Nested Classes

Programming Safe Agents in Blueprint. Alex Muscar University of Craiova

MASSACHVSETTS INSTITVTE OF TECHNOLOGY Department of Electrical Engineering and Computer Science. Issued: Wed. 26 April 2017 Due: Wed.

Swift 5, ABI Stability and

Context Tokens for Parallel Algorithms

Serverless Single Page Web Apps, Part Four. CSCI 5828: Foundations of Software Engineering Lecture 24 11/10/2016

Intro. Scheme Basics. scm> 5 5. scm>

CS 351 Design of Large Programs Programming Abstractions

Reactive Programming with Vert.x

Project. Threads. Plan for today. Before we begin. Thread. Thread. Minimum submission. Synchronization TSP. Thread synchronization. Any questions?

UI-Testing, Reactive Programming and some Kotlin.

Multithreading and Interactive Programs

! How is a thread different from a process? ! Why are threads useful? ! How can POSIX threads be useful?

Written Presentation: JoCaml, a Language for Concurrent Distributed and Mobile Programming

DNParallel - Version: 3. TPL Dataflow

Generating Continuation Passing Style Code for the Co-op Language

PERL 6 and PARROT An Overview. Presentation for NYSA The New York System Administrators Association

!! How is a thread different from a process? !! Why are threads useful? !! How can POSIX threads be useful?

Reactive Programming in Java. Copyright - Syncogni Consulting Pvt Ltd. All rights reserved.

A Brief History of Distributed Programming: RPC. YOW Brisbane 2016

COPYRIGHTED MATERIAL. Table of Contents. Foreword... xv. About This Book... xvii. About The Authors... xxiii. Guide To The Reader...

Programmazione Avanzata e Paradigmi Ingegneria e Scienze Informatiche - UNIBO a.a 2013/2014 Lecturer: Alessandro Ricci

Chair of Software Engineering. Java and C# in depth. Carlo A. Furia, Marco Piccioni, Bertrand Meyer. Java: concurrency

CMSC 132: Object-Oriented Programming II. Threads in Java

Composable Concurrency in Perl 6. Jonathan Worthington

MultiThreading 07/01/2013. Session objectives. Introduction. Introduction. Advanced Java Programming Course

Advanced Java Programming Course. MultiThreading. By Võ Văn Hải Faculty of Information Technologies Industrial University of Ho Chi Minh City

DOMjudge team manual. Summary. Reading and writing. Submitting solutions. Viewing scores, submissions, etc.

Introduction to Locks. Intrinsic Locks

Async Programming & Networking. CS 475, Spring 2018 Concurrent & Distributed Systems

Reaktive Anwendungen mit RxJava. Dr. Michael Menzel

Contents. Figures. Tables. Examples. Foreword. Preface. 1 Basics of Java Programming 1. xix. xxi. xxiii. xxvii. xxix

A Standard Programmatic Interface for Asynchronous Operations

M/s. Managing distributed workloads. Language Reference Manual. Miranda Li (mjl2206) Benjamin Hanser (bwh2124) Mengdi Lin (ml3567)

Web Application Development

Multithreaded Programming Part II. CSE 219 Stony Brook University, Department of Computer Science

Contribution:javaMultithreading Multithreading Prof. Dr. Ralf Lämmel Universität Koblenz-Landau Software Languages Team

Lecture 27: Safety and Liveness Properties, Java Synchronizers, Dining Philosophers Problem

Composable Concurrency in Perl 6. Jonathan Worthington

A Deep Dive Into Kotlin

Control Abstraction. Hwansoo Han

15CS45 : OBJECT ORIENTED CONCEPTS

Transcription:

Introduction to Coroutines Roman Elizarov elizarov at JetBrains

Asynchronous programming

How do we write code that waits for something most of the time?

A toy problem Kotlin 1 fun requesttoken(): Token { // makes request for a token & waits return token // returns result when received

A toy problem Kotlin 2 fun requesttoken(): Token { fun createpost(token: Token, item: Item): Post { // sends item to the server & waits return post // returns resulting post

A toy problem Kotlin 3 fun requesttoken(): Token { fun createpost(token: Token, item: Item): Post { fun processpost(post: Post) { // does some local processing of result

A toy problem Kotlin fun requesttoken(): Token { fun createpost(token: Token, item: Item): Post { fun processpost(post: Post) { 1 2 3 fun postitem(item: Item) { val token = requesttoken() val post = createpost(token, item) processpost(post) Can be done with threads!

Threads Is anything wrong with it? 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) { fun postitem(item: Item) { val token = requesttoken() val post = createpost(token, item) processpost(post)

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

Sort of Callbacks to the rescue

Callbacks: before 1 fun requesttoken(): Token { // makes request for a token & waits return token // returns result when received

Callbacks: after 1 callback fun requesttokenasync(cb: (Token) -> Unit) { // makes request for a token, invokes callback when done // returns immediately

Callbacks: before 2 fun requesttokenasync(cb: (Token) -> Unit) { fun createpost(token: Token, item: Item): Post { // sends item to the server & waits return post // returns resulting post

Callbacks: after 2 fun requesttokenasync(cb: (Token) -> Unit) { fun createpostasync(token: Token, item: Item, callback cb: (Post) -> Unit) { // sends item to the server, invokes callback when done // returns immediately

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 1 fun requesttokenasync(cb: (Token) -> Unit) { // makes request for a token, invokes callback when done // returns immediately

Futures: after 1 future fun requesttokenasync(): Promise<Token> { // makes request for a token // returns promise for a future result immediately

Futures: before 2 fun requesttokenasync(): Promise<Token> { fun createpostasync(token: Token, item: Item, cb: (Post) -> Unit) { // sends item to the server, invokes callback when done // returns immediately

Futures: after 2 fun requesttokenasync(): Promise<Token> { future fun createpostasync(token: Token, item: Item): Promise<Post> { // sends item to the server // returns promise for a future result immediately

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) { Composable & propagates exceptions fun postitem(item: Item) { requesttokenasync().thencompose { token -> createpostasync(token, item).thenaccept { post -> processpost(post) 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 1 fun requesttokenasync(): Promise<Token> { // makes request for a token // returns promise for a future result immediately

Coroutines: after 1 suspend fun requesttoken(): Token { // makes request for a token & suspends return token // returns result when received

Coroutines: after 1 natural signature suspend fun requesttoken(): Token { // makes request for a token & suspends return token // returns result when received

Coroutines: before 2 suspend fun requesttoken(): Token { fun createpostasync(token: Token, item: Item): Promise<Post> { // sends item to the server // returns promise for a future result immediately

Coroutines: after 2 suspend fun requesttoken(): Token { suspend fun createpost(token: Token, item: Item): Post { // sends item to the server & suspends return post // returns result when received

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) { suspension points suspend fun postitem(item: Item) { val token = requesttoken() val post = createpost(token, item) processpost(post)

Bonus features Regular loops for ((token, item) in list) { createpost(token, item)

Regular exception handing Bonus features try { createpost(token, item) catch (e: BadTokenException) {

Regular higher-order functions Bonus features file.readlines().foreach { line -> createpost(token, line.toitem()) foreach, let, apply, repeat, filter, map, use, etc Everything like in blocking code

Suspending functions

Retrofit async interface Service { fun createpost(token: Token, item: Item): Call<Post>

Retrofit async interface Service { future fun createpost(token: Token, item: Item): Call<Post>

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> natural signature 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() Suspending extension function from integration library

Beyond sequential Composition

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) suspending lambda 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) 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) { Can suspend execution 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) { A regular function cannot Can suspend execution 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) { A regular function cannot Can suspend execution fun postitem(item: Item) { val token = requesttoken() val post = createpost(token, item) processpost(post) One cannot simply invoke a suspending function

Launch coroutine builder fun postitem(item: Item) { launch { val token = requesttoken() val post = createpost(token, item) processpost(post)

Returns immediately, coroutine works in background thread pool fun postitem(item: Item) { launch { val token = requesttoken() val post = createpost(token, item) processpost(post) Fire and forget!

fun postitem(item: Item) { launch { 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 fun postitem(item: Item) { launch(ui) { val token = requesttoken() val post = createpost(token, item) processpost(post) And it gets executed on UI thread

Where s the magic of launch?

A regular function fun launch( context: CoroutineContext = DefaultDispatcher, block: suspend () -> Unit ): Job {

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 requesttoken(): Token { suspend fun createpost(token: Token, item: Item): Post { fun processpost(post: Post) { Kotlin suspend fun postitem(item: Item) { val token = requesttoken() val post = createpost(token, item) processpost(post)

Classic-way async Task<Token> requesttoken() { async Task<Post> createpost(token token, Item item) { void processpost(post post) { C# approach to the same problem (also Python, TS, Dart, coming to JS) C# async Task postitem(item item) { var token = await requesttoken(); var post = await createpost(token, item); processpost(post);

Classic-way async Task<Token> requesttoken() { async Task<Post> createpost(token token, Item item) { void processpost(post post) { mark with async C# async Task postitem(item item) { var token = await requesttoken(); var post = await createpost(token, item); processpost(post);

Classic-way async Task<Token> requesttoken() { async Task<Post> createpost(token token, Item item) { void processpost(post post) { C# async Task postitem(item item) { var token = await requesttoken(); var post = await createpost(token, item); processpost(post); use await to suspend

Classic-way async Task<Token> requesttoken() { async Task<Post> createpost(token token, Item item) { void processpost(post post) { C# returns a future async Task postitem(item item) { var token = await requesttoken(); var post = await createpost(token, item); processpost(post);

Why no await keyword in Kotlin? The problem with async C# requesttoken() VALID > produces Task<Token> concurrent behavior default C# await requesttoken() VALID > produces Token sequential behavior

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 C# async Task<Image> loadimageasync(string name) {

Use-case for async C# async Task<Image> loadimageasync(string name) { var promise1 = loadimageasync(name1); var promise2 = loadimageasync(name2); Start multiple operations concurrently

Use-case for async C# async Task<Image> loadimageasync(string name) { var promise1 = loadimageasync(name1); var promise2 = loadimageasync(name2); var image1 = await promise1; var image2 = await promise2; and then wait for them

Use-case for async C# async Task<Image> loadimageasync(string name) { var promise1 = loadimageasync(name1); var promise2 = loadimageasync(name2); var image1 = await promise1; var image2 = await promise2; var result = combineimages(image1, image2);

Kotlin async function Kotlin fun loadimageasync(name: String): Deferred<Image> = async {

Kotlin async function A regular function Kotlin fun loadimageasync(name: String): Deferred<Image> = async {

Kotlin async function Kotlin s future type Kotlin fun loadimageasync(name: String): Deferred<Image> = async {

Kotlin async function Kotlin fun loadimageasync(name: String): Deferred<Image> = async { async coroutine builder

Kotlin async function Kotlin fun loadimageasync(name: String): Deferred<Image> = async { val deferred1 = loadimageasync(name1) val deferred2 = loadimageasync(name2) Start multiple operations concurrently

Kotlin async function Kotlin fun loadimageasync(name: String): Deferred<Image> = async { val deferred1 = loadimageasync(name1) val deferred2 = loadimageasync(name2) val image1 = deferred1.await() val image2 = deferred2.await() await function and then wait for them Suspends until deferred is complete

Kotlin async function Kotlin 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)

Using async function when needed Is defined as suspending function, not async suspend fun loadimage(name: String): Image {

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 Kotlin requesttoken() VALID > produces Token sequential behavior default Kotlin async { requesttoken() VALID > produces Deferred<Token> concurrent behavior

Coroutines

What are coroutines conceptually?

What are coroutines conceptually? Coroutines are like very light-weight threads

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 fun main(args: Array<String>) = runblocking<unit> { val jobs = List(100_000) { launch { delay(1000l) print(".") jobs.foreach { it.join() Suspends for 1 second

Example fun main(args: Array<String>) = runblocking<unit> { val jobs = List(100_000) { launch { delay(1000l) print(".") jobs.foreach { it.join() We can join a job just like a thread

Demo

Example fun main(args: Array<String>) = runblocking<unit> { val jobs = List(100_000) { launch { delay(1000l) print(".") jobs.foreach { it.join() Prints 100k dots after one second delay Try that with 100k threads!

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>) { val jobs = List(100_000) { thread { Thread.sleep(1000L) print(".") jobs.foreach { it.join()

Demo

Example Exception in thread "main" java.lang.outofmemoryerror: unable to create new native thread fun main(args: Array<String>) { val jobs = List(100_000) { thread { Thread.sleep(1000L) print(".") jobs.foreach { it.join()

Java interop

Java 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) { Kotlin fun loadandcombineasync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadimageasync(name1) val future2 = loadimageasync(name2) combineimages(future1.await(), future2.await())

Java CompletableFuture<Image> loadimageasync(string name) { Kotlin fun loadandcombineasync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadimageasync(name1) val future2 = loadimageasync(name2) combineimages(future1.await(), future2.await())

Java CompletableFuture<Image> loadimageasync(string name) { Kotlin fun loadandcombineasync( name1: String, future coroutine builder name2: String ): CompletableFuture<Image> = future { val future1 = loadimageasync(name1) val future2 = loadimageasync(name2) combineimages(future1.await(), future2.await())

Java CompletableFuture<Image> loadimageasync(string name) { Kotlin fun loadandcombineasync( name1: String, name2: String ): CompletableFuture<Image> = future { val future1 = loadimageasync(name1) val future2 = loadimageasync(name2) combineimages(future1.await(), future2.await())

Java CompletableFuture<Image> loadimageasync(string name) { Kotlin 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

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 Synchronous with invoker val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next()) // 1 println(iter.next()) // 2

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

Thank you Roman Elizarov elizarov at JetBrains relizarov Any questions? #kotlinconf17