fresh async with kotlin @ qconsf 2017

Post on 21-Jan-2018

62 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

FreshAsyncWithKotlin

PresentedatQCon SF,2017/RomanElizarov@JetBrains

Speaker:RomanElizarov

• 16+yearsexperience• Previouslydevelopedhigh-perftradingsoftware@Devexperts• Teachconcurrent&distributedprogramming@St.PetersburgITMOUniversity• Chiefjudge@NorthernEurasiaContest/ACMICPC• NowteamleadinKotlinLibraries@JetBrains

Pragmatic.Concise.Modern.InteroperablewithJava.

AsynchronousProgramming

Howdowewritecodethatwaitsforsomethingmostofthetime?

AtoyproblemKotlin fun requestToken(): Token {

// makes request for a token & waitsreturn 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

}

AtoyproblemKotlin

2

fun requestToken(): Token { … }fun createPost(token: Token, item: Item): Post { … }fun processPost(post: Post) {

// does some local processing of result}

AtoyproblemKotlin

3

fun requestToken(): Token { … }fun createPost(token: Token, item: Item): Post { … }fun processPost(post: Post) { … }

AtoyproblemKotlin

fun postItem(item: Item) {val token = requestToken()val post = createPost(token, item)processPost(post)

}

123

Canbedonewiththreads!

fun requestToken(): Token {// makes request for a token // blocks the thread waiting for resultreturn 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)

}

Isanythingwrongwithit?

Howmanythreadswecanhave?

100🙂

Howmanythreadswecanhave?

1000😅

Howmanythreadswecanhave?

10000😩

Howmanythreadswecanhave?

100000😵

CallbackstotherescueSortof…

Callbacks:beforefun requestToken(): Token {

// makes request for a token & waitsreturn token // returns result when received

}

1

Callbacks:afterfun requestTokenAsync(cb: (Token) -> Unit) {

// makes request for a token, invokes callback when done// returns immediately

}

1callback

Callbacks:beforefun requestTokenAsync(cb: (Token) -> Unit) { … }fun createPost(token: Token, item: Item): Post {

// sends item to the server & waits return post // returns resulting post

}

2

Callbacks:afterfun requestTokenAsync(cb: (Token) -> Unit) { … }fun createPostAsync(token: Token, item: Item,

cb: (Post) -> Unit) {// sends item to the server, invokes callback when done// returns immediately

}

2callback

Callbacks:beforefun 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:afterfun 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“callbackhell”

Thisissimplified.Handlingexceptionsmakesitarealmess

Futures/Promises/RxtotherescueSortof…

Futures:beforefun requestTokenAsync(cb: (Token) -> Unit) {

// makes request for a token, invokes callback when done// returns immediately

}

1

Futures:afterfun requestTokenAsync(): Promise<Token> {

// makes request for a token// returns promise for a future result immediately

}

1future

Futures:beforefun 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:afterfun requestTokenAsync(): Promise<Token> { … }fun createPostAsync(token: Token, item: Item): Promise<Post> {

// sends item to the server // returns promise for a future result immediately

}

future2

Futures:beforefun 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:afterfun 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 &propagatesexceptions

Nonestingindentation

Futures:afterfun 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) }}

Butallthosecombinators…

KotlincoroutinestotherescueLet’sgetreal

Coroutines:beforefun requestTokenAsync(): Promise<Token> {

// makes request for a token// returns promise for a future result immediately

}

1

Coroutines:aftersuspend fun requestToken(): Token {

// makes request for a token & suspendsreturn token // returns result when received

}

1naturalsignature

Coroutines:beforesuspend 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:aftersuspend fun requestToken(): Token { … }suspend fun createPost(token: Token, item: Item): Post {

// sends item to the server & suspendsreturn post // returns result when received

}

2naturalsignature

Coroutines:beforesuspend 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:aftersuspend 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:aftersuspend 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)

}

Likeregular code

Coroutines:aftersuspend 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)

}

suspensionpoints

• Regularloops

Bonusfeatures

for ((token, item) in list) {createPost(token, item)

}

• Regularexceptionhanding

Bonusfeatures

try { createPost(token, item)

} catch (e: BadTokenException) { …

}

• Regularhigher-orderfunctions

• forEach,let,apply,repeat,filter,map,use,etc

Bonusfeatures

file.readLines().forEach { line ->createPost(token, line.toItem())

}

• Customhigher-orderfunctions

Bonusfeatures

val post = retryIO {createPost(token, item)

}

Everythinglikeinblockingcode

Howdoesitwork?Aquickpeekbehindthescenes

Kotlinsuspendingfunctions

callback

Kotlin

Java/JVM

suspend fun createPost(token: Token, item: Item): Post { … }

Object createPost(Token token, Item item, Continuation<Post> cont) { … }

Kotlinsuspendingfunctions

callback

Kotlin

Java/JVM

Continuationisagenericcallbackinterface

suspend fun createPost(token: Token, item: Item): Post { … }

Object createPost(Token token, Item item, Continuation<Post> cont) { … }

interface Continuation<in T> {val context: CoroutineContextfun resume(value: T)fun resumeWithException(exception: Throwable)

}

Kotlinsuspendingfunctions

callback

Kotlin

Java/JVM

suspend fun createPost(token: Token, item: Item): Post { … }

Object createPost(Token token, Item item, Continuation<Post> cont) { … }

interface Continuation<in T> {val context: CoroutineContextfun resume(value: T)fun resumeWithException(exception: Throwable)

}

Kotlinsuspendingfunctions

callback

Kotlin

Java/JVM

suspend fun createPost(token: Token, item: Item): Post { … }

Object createPost(Token token, Item item, Continuation<Post> cont) { … }

interface Continuation<in T> {val context: CoroutineContextfun resume(value: T)fun resumeWithException(exception: Throwable)

}

Kotlinsuspendingfunctions

callback

Kotlin

Java/JVM

suspend fun createPost(token: Token, item: Item): Post { … }

Object createPost(Token token, Item item, Continuation<Post> cont) { … }

interface Continuation<in T> {val context: CoroutineContextfun resume(value: T)fun resumeWithException(exception: Throwable)

}

CodewithsuspensionpointsKotlin

Java/JVMCompilestostatemachine(simplifiedcodeshown)

val token = requestToken()val post = createPost(token, item)processPost(post)

switch (cont.label) {case 0:

cont.label = 1;requestToken(cont);break;

case 1:Token token = (Token) prevResult;cont.label = 2;createPost(token, item, cont);break;

case 2:Post post = (Post) prevResult;processPost(post);break;

}

CodewithsuspensionpointsKotlin

Java/JVM

val token = requestToken()val post = createPost(token, item)processPost(post)

switch (cont.label) {case 0:

cont.label = 1;requestToken(cont);break;

case 1:Token token = (Token) prevResult;cont.label = 2;createPost(token, item, cont);break;

case 2:Post post = (Post) prevResult;processPost(post);break;

}

IntegrationZoooffuturesonJVM

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

}

Retrofitasync

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

}

suspend fun createPost(token: Token, item: Item): Post =serviceInstance.createPost(token, item).await()

naturalsignature

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

}

suspend fun createPost(token: Token, item: Item): Post =serviceInstance.createPost(token, item).await()

Suspendingextensionfunctionfromintegrationlibrary

suspend fun <T> Call<T>.await(): T {…

}

Callbackseverywhere

suspend fun <T> Call<T>.await(): T {enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {// todo

}

override fun onFailure(call: Call<T>, t: Throwable) {// todo

}})

}

suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {if (response.isSuccessful)

cont.resume(response.body()!!)else

cont.resumeWithException(ErrorResponse(response))}

override fun onFailure(call: Call<T>, t: Throwable) {cont.resumeWithException(t)

}})

}

suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T

suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T

suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T

Regularfunction

Inspiredbycall/cc fromScheme

suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {if (response.isSuccessful)

cont.resume(response.body()!!)else

cont.resumeWithException(ErrorResponse(response))}

override fun onFailure(call: Call<T>, t: Throwable) {cont.resumeWithException(t)

}})

}

Installcallback

suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {if (response.isSuccessful)

cont.resume(response.body()!!)else

cont.resumeWithException(ErrorResponse(response))}

override fun onFailure(call: Call<T>, t: Throwable) {cont.resumeWithException(t)

}})

}

Installcallback

suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {if (response.isSuccessful)

cont.resume(response.body()!!)else

cont.resumeWithException(ErrorResponse(response))}

override fun onFailure(call: Call<T>, t: Throwable) {cont.resumeWithException(t)

}})

}

Analyzeresponse

suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {if (response.isSuccessful)

cont.resume(response.body()!!)else

cont.resumeWithException(ErrorResponse(response))}

override fun onFailure(call: Call<T>, t: Throwable) {cont.resumeWithException(t)

}})

}

Analyzeresponse

suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->enqueue(object : Callback<T> {

override fun onResponse(call: Call<T>, response: Response<T>) {if (response.isSuccessful)

cont.resume(response.body()!!)else

cont.resumeWithException(ErrorResponse(response))}

override fun onFailure(call: Call<T>, t: Throwable) {cont.resumeWithException(t)

}})

}That’sall

Out-of-theboxintegrations

kotlinx-coroutines-core

jdk8

guava

nio

reactor

rx1

rx2

CoroutinebuildersHowcanwestartacoroutine?

Coroutinesrevisitedsuspend 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)

}

Coroutinesrevisitedsuspend 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)

}

Coroutinesrevisitedsuspend 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: Suspendfunction'requestToken'shouldbecalledonlyfromacoroutineoranothersuspendfunction

Coroutinesrevisitedsuspend 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)

}

Cansuspend execution

Coroutinesrevisitedsuspend 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)

}

Cansuspend executionAregularfunctioncannot

Coroutinesrevisitedsuspend 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)

}

Cansuspend executionAregularfunctioncannot

Onecannotsimplyinvokeasuspendingfunction

Launch

fun postItem(item: Item) {launch {

val token = requestToken()val post = createPost(token, item)processPost(post)

}}

coroutinebuilder

fun postItem(item: Item) {launch {

val token = requestToken()val post = createPost(token, item)processPost(post)

}}

Fireandforget!

Returnsimmediately,coroutineworksinbackgroundthreadpool

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)

}}

UIContext

Justspecifythecontext

fun postItem(item: Item) {launch(UI) {

val token = requestToken()val post = createPost(token, item)processPost(post)

}}

UIContext

AnditgetsexecutedonUIthread

Where’sthemagicoflaunch?

fun launch(context: CoroutineContext = DefaultDispatcher,block: suspend () -> Unit

): Job { … }

Aregularfunction

fun launch(context: CoroutineContext = DefaultDispatcher,block: suspend () -> Unit

): Job { … } suspendinglambda

fun launch(context: CoroutineContext = DefaultDispatcher,block: suspend () -> Unit

): Job { … }

async /awaitTheclassicapproach

Kotlin-way

suspend fun postItem(item: Item) {val token = requestToken()val post = createPost(token, item)processPost(post)

}

suspend fun requestToken(): Token { … }suspend fun createPost(token: Token, item: Item): Post { … }fun processPost(post: Post) { … }

Kotlin

async Task postItem(Item item) { var token = await requestToken(); var post = await createPost(token, item); processPost(post);

}

Classic-way

C#approachtothesameproblem(alsoPython,TS,Dart,comingtoJS)

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);

}

Classic-way

markwithasync

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);

}

Classic-way

useawaittosuspend

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);

}

Classic-way

returnsafuture

async Task<Token> requestToken() { … }async Task<Post> createPost(Token token, Item item) { … }void processPost(Post post) { … }

C#

Whynoawait keywordinKotlin?

Theproblemwithasync

requestToken() VALID –>producesTask<Token>

await requestToken() VALID –>producesToken

concurrentbehavior

sequentialbehavior

C#

C#

default

ConcurrencyishardConcurrencyhastobeexplicit

Kotlinsuspendingfunctionsaredesignedtoimitatesequential behavior

bydefault

ConcurrencyishardConcurrencyhastobeexplicit

KotlinapproachtoasyncConcurrencywhereyouneedit

Use-caseforasync

async Task<Image> loadImageAsync(String name) { … } C#

Use-caseforasync

var promise1 = loadImageAsync(name1);var promise2 = loadImageAsync(name2);

async Task<Image> loadImageAsync(String name) { … }

Startmultipleoperationsconcurrently

C#

Use-caseforasync

var promise1 = loadImageAsync(name1);var promise2 = loadImageAsync(name2);

var image1 = await promise1;var image2 = await promise2;

async Task<Image> loadImageAsync(String name) { … }

andthenwaitforthem

C#

Use-caseforasync

var result = combineImages(image1, image2);

var promise1 = loadImageAsync(name1);var promise2 = loadImageAsync(name2);

var image1 = await promise1;var image2 = await promise2;

async Task<Image> loadImageAsync(String name) { … } C#

Kotlinasync function

fun loadImageAsync(name: String): Deferred<Image> = async { … }

Kotlin

Kotlinasync function

fun loadImageAsync(name: String): Deferred<Image> = async { … }

Aregularfunction

Kotlin

Kotlinasync function

fun loadImageAsync(name: String): Deferred<Image> = async { … }

Kotlin’s futuretype

Kotlin

Kotlinasync function

fun loadImageAsync(name: String): Deferred<Image> = async { … }

async coroutinebuilder

Kotlin

Kotlinasync function

fun loadImageAsync(name: String): Deferred<Image> = async { … }

val deferred1 = loadImageAsync(name1)val deferred2 = loadImageAsync(name2)

Startmultipleoperationsconcurrently

Kotlin

Kotlinasync function

fun loadImageAsync(name: String): Deferred<Image> = async { … }

val deferred1 = loadImageAsync(name1)val deferred2 = loadImageAsync(name2)

val image1 = deferred1.await()val image2 = deferred2.await() andthenwaitforthem

awaitfunction

Suspendsuntildeferrediscomplete

Kotlin

Kotlinasync 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

Usingasync functionwhenneeded

suspend fun loadImage(name: String): Image { … }

Isdefinedassuspendingfunction,notasync

Usingasync functionwhenneeded

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())

}

Usingasync functionwhenneeded

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())

}

Usingasync functionwhenneeded

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())

}

Usingasync functionwhenneeded

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 approachtoasync

requestToken() VALID –>producesToken

async { requestToken() } VALID –>producesDeferred<Token>

sequentialbehavior

concurrentbehavior

Kotlin

Kotlin

default

Whatarecoroutinesconceptually?

Whatarecoroutinesconceptually?Coroutinesarelikevery light-weightthreads

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 Thiscoroutinebuilderrunscoroutineinthecontextofinvokerthread

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

Suspendsfor1second

fun main(args: Array<String>) = runBlocking<Unit> {val jobs = List(100_000) {

launch {delay(1000L)print(".")

}}jobs.forEach { it.join() }

}

Example

Wecanjoinajobjustlikeathread

fun main(args: Array<String>) = runBlocking<Unit> {val jobs = List(100_000) {

launch {delay(1000L)print(".")

}}jobs.forEach { it.join() }

}

Example

Trythatwith100kthreads!

Prints100kdotsafteroneseconddelay

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

fun main(args: Array<String>) {val jobs = List(100_000) {

thread {Thread.sleep(1000L)print(".")

}}jobs.forEach { it.join() }

}

Example

Exceptioninthread"main"java.lang.OutOfMemoryError:unabletocreatenewnativethread

JavainteropCanweuseKotlincoroutineswithJavacode?

Javainterop

CompletableFuture<Image> loadImageAsync(String name) { … }Java

CompletableFuture<Image> loadImageAsync(String name) { … }

CompletableFuture<Image> loadAndCombineAsync(String name1, String name2)

Java

ImagineimplementingitinJava…

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) { … }Java

fun loadAndCombineAsync(name1: String, name2: String

): CompletableFuture<Image> =…

Kotlin

CompletableFuture<Image> loadImageAsync(String name) { … }Java

fun loadAndCombineAsync(name1: String, name2: String

): CompletableFuture<Image> =future {

val future1 = loadImageAsync(name1)val future2 = loadImageAsync(name2)combineImages(future1.await(), future2.await())

}

Kotlin

CompletableFuture<Image> loadImageAsync(String name) { … }Java

fun loadAndCombineAsync(name1: String, name2: String

): CompletableFuture<Image> =future {

val future1 = loadImageAsync(name1)val future2 = loadImageAsync(name2)combineImages(future1.await(), future2.await())

}

Kotlinfuturecoroutinebuilder

CompletableFuture<Image> loadImageAsync(String name) { … }Java

fun loadAndCombineAsync(name1: String, name2: String

): CompletableFuture<Image> =future {

val future1 = loadImageAsync(name1)val future2 = loadImageAsync(name2)combineImages(future1.await(), future2.await())

}

Kotlin

CompletableFuture<Image> loadImageAsync(String name) { … }Java

fun loadAndCombineAsync(name1: String, name2: String

): CompletableFuture<Image> =future {

val future1 = loadImageAsync(name1)val future2 = loadImageAsync(name2)combineImages(future1.await(), future2.await())

}

Kotlin

BeyondasynchronouscodeKotlin’s approachtogenerate/yield– synchronouscoroutines

Fibonaccisequence

val fibonacci: Sequence<Int> = …

Fibonaccisequence

val fibonacci = buildSequence {var cur = 1var next = 1while (true) {

yield(cur) val tmp = cur + nextcur = nextnext = tmp

}}

Fibonaccisequence

val fibonacci = buildSequence {var cur = 1var next = 1while (true) {

yield(cur) val tmp = cur + nextcur = nextnext = tmp

}}

Acoroutinebuilderwithrestrictedsuspension

Fibonaccisequence

val fibonacci = buildSequence {var cur = 1var next = 1while (true) {

yield(cur) val tmp = cur + nextcur = nextnext = tmp

}}

Asuspendingfunction

Thesamebuildingblocks

public fun <T> buildSequence(builderAction: suspend SequenceBuilder<T>.() -> Unit

): Sequence<T> { … }

Thesamebuildingblocks

public fun <T> buildSequence(builderAction: suspend SequenceBuilder<T>.() -> Unit

): Sequence<T> { … }

Resultisasynchronous sequence

Thesamebuildingblocks

public fun <T> buildSequence(builderAction: suspend SequenceBuilder<T>.() -> Unit

): Sequence<T> { … }

Suspendinglambdawithreceiver

Thesamebuildingblocks

public fun <T> buildSequence(builderAction: suspend SequenceBuilder<T>.() -> Unit

): Sequence<T> { … }

@RestrictsSuspensionabstract class SequenceBuilder<in T> {

abstract suspend fun yield(value: T)}

Coroutineisrestrictedonlytosuspendingfunctionsdefinedhere

LibraryvsLanguageKeepingthecorelanguagesmall

Classicasync

async/awaitgenerate/yield Keywords

Kotlincoroutines

suspend Modifier

Kotlincoroutines

Standardlibrary

Kotlincoroutines

Standardlibrary

kotlinx-coroutines

launch,async,runBlocking,future,delay,

Job,Deferred,etc

http://github.com/kotlin/kotlinx.coroutines

ExperimentalinKotlin1.1&1.2

Coroutinescanbeused inproduction

Backwardscompatibleinside1.1&1.2

Tobefinalizedinthefuture

Thankyou

Anyquestions?

Slidesareavailableatwww.slideshare.net/elizarovemailmetoelizarov atgmail

relizarov

top related