Slide 1

Slide 1 text

KotlinConf 2018 ϫʔΫγϣοϓʹࢀՃͯ͠ ͖ͨ ͋Μ͍͟Ώ͖ʢ@yanzmʣ KotlinConf 2018 ใࠂձ

Slide 2

Slide 2 text

Workshop day • 10݄3೔ʢKotlinConf day1ʣ • ΧϯϑΝϨϯεͱ͸ผྉۚ : €649 • 9:00 ʙ 17:00 • ே͝͸Μɾன͝͸Μ͋Γ • ձ৔͸ΧϯϑΝϨϯεͱಉ͡ • https://kotlinconf.com/workshops/

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Workshops • Up and running with Kotlin by Svetlana Isakova • Asynchronous Programming with Kotlin by Roman Elizarov • Developing Android Apps in Kotlin by Florina Muntenescu and Sean McQuillan • Building a Full Stack Web Application in Kotlin by Garth Gilmour • Refactoring to Kotlin by Duncan McGregor and Nat Pryce

Slide 9

Slide 9 text

Asynchronous Programming with Kotlin • ߨࢣ : Roman Elizarov • https://github.com/elizarov • ಺༰ : coroutines

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

ࣄલ४උ • ࠷৽ͷ IntelliJ IDEA (CE Մ) ΛΠϯετʔϧ͓ͯ͘͠ • Kotlin plugin ͷ࠷৽ͷ EAP 1.3 version ΛΠϯετʔϧ͓ͯ͘͠ • [Tools] → [Kotlin] → [Con fi gure Kotlin Plugin Updates] → Early Access Preview 1.3 → Check & Install the latest version • Github ϩάΠϯ༻ͷτʔΫϯ • [Settings] →[Developer Setting] → Personal Access Tokens → Generate New Token

Slide 14

Slide 14 text

Outline • Asynchronous programming, Introduction to Coroutines • Coroutines vs Threads, Context and Cancellation • Coroutines and Concurrency • CSP with Channels and Actors

Slide 15

Slide 15 text

αϯϓϧϓϩδΣΫτ • project/ContributorsUI.main() • σεΫτοϓΞϓϦʢSwingར༻ʣ • GitHub ͔Β kotlin Organization ͷϦϙδτϦҰཡΛऔ ಘ͠ɺ֤ϦϙδτϦͷ contributors Λऔಘ͠ूܭ͢Δ • part1async/ ʙ part4csp/ • খ͍͞ demo ίʔυू

Slide 16

Slide 16 text

• Kotlin Organization ͷϦϙδτϦΛऔಘ • List • ϦϙδτϦ͝ͱ Contributors Λऔಘ • List • ϢʔβʔͷॏෳΛ fl attenͯ͠ूܭ Repo1 - User11 - User12 - … Repo2 - User21 - User22 - … …

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

enum class Variant { BLOCKING, // Request1Blocking BACKGROUND, // Request2Background CALLBACKS, // Request3Callbacks COROUTINE, // Request4Coroutine PROGRESS, // Request5Progress CANCELLABLE, // Request5Progress (too) CONCURRENT, // Request6Concurrent GATHER, // Request8Gather ACTOR // Request9Actor }

Slide 19

Slide 19 text

Programming styles • 1. Blocking threads • 2. Callbacks • 3. Futures • 4. Kotlin coroutines

Slide 20

Slide 20 text

Programming styles • 1. Blocking threads • 2. Callbacks • 3. Futures • 4. Kotlin coroutines COROUTINE, // Request4Coroutine PROGRESS, // Request5Progress CANCELLABLE, // Request5Progress (t CONCURRENT, // Request6Concurrent GATHER, // Request8Gather ACTOR // Request9Actor FUTURE, // Request7Future CALLBACKS, // Request3Callbacks BACKGROUND, // Request2Background

Slide 21

Slide 21 text

΢ΥʔϛϯάΞοϓ data class User( val login: String, val contributions: Int ) fun List.aggregate(): List = TODO List ͷத͔Βॏෳͨ͠ login ͷ User Λ̍ͭʹ·ͱΊΔ ·ͱΊΔͱ͖ contributions Λ଍͠߹ΘͤΔ contributions ͷଟ͍ॱʹιʔτ͢Δ

Slide 22

Slide 22 text

΢ΥʔϛϯάΞοϓ fun List.aggregate(): List = groupingBy { it.login } .reduce { login, a, b -> User(login, a.contributions + b.contributions) } .values .sortedByDescending { it.contributions } data class User( val login: String, val contributions: Int ) List ͷத͔Βॏෳͨ͠ login ͷ User Λ̍ͭʹ·ͱΊΔ ·ͱΊΔͱ͖ contributions Λ଍͠߹ΘͤΔ contributions ͷଟ͍ॱʹιʔτ͢Δ

Slide 23

Slide 23 text

Background fun loadContributorsBackground(req: RequestData, callback: (List) -> Unit) { thread { val users = loadContributorsBlocking(req) callback(users) } } εϨουͰ

Slide 24

Slide 24 text

Callbacks fun loadContributorsCallbacks(req: RequestData, callback: (List) -> Unit) { val service = createGitHubService(req.username, req.password) service.listOrgRepos(req.org).responseCallback { repos -> … } } inline fun Call.responseCallback(crossinline callback: (T) -> Unit) { enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { checkResponse(response) callback(response.body()!!) } override fun onFailure(call: Call, t: Throwable) { log.error("Call failed", t) } }) } Retro fi t ͷ enqueue Λར༻

Slide 25

Slide 25 text

Coroutines launch { val users = loadContributors(req) updateResults(users) } suspend fun loadContributors(req: RequestData) : List { val service = createGitHubService(req.username, req.password) val repos = service.listOrgRepos(req.org).await() val contribs = repos.flatMap { repo -> val users = service.listRepoContributors(req.org, repo.name).await() users }.aggregate() return contribs } loadContributors() ෦෼͸ blocking ͱಉ͡

Slide 26

Slide 26 text

Progress suspend fun loadContributorsProgress(req: RequestData, callback: (List) -> Unit) { val service = createGitHubService(req.username, req.password) val repos = service.listOrgRepos(req.org).await() var contribs = listOf() for (repo in repos) { val users = service.listRepoContributors(req.org, repo.name).await() contribs = (contribs + users).aggregateSlow() callback(contribs) } } Coroutines + Progress ϦϙδτϦϩʔυ͝ͱʹ callback ݺͼग़͠

Slide 27

Slide 27 text

Cancellable private fun Job.updateCancelJob() { updateEnabled(false) val listener = ActionListener { cancel() } cancel.addActionListener(listener) launch { join() updateEnabled(true) cancel.removeActionListener(listener) } } ΩϟϯηϧϘλϯ͕ԡ͞ΕͨΒ Job Λ cancel() launch { loadContributorsProgress(req) { users -> updateResults(users) } }.updateCancelJob()

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

Concurrent suspend fun loadContributorsConcurrent(req: RequestData): List = coroutineScope { val service = createGitHubService(req.username, req.password) val repos = service.listOrgRepos(req.org).await() val contribs = repos.map { repo -> async { val users = service.listRepoContributors(req.org, repo.name).await() users } }.awaitAll().flatten().aggregate() contribs } async ͰϦϙδτϦ͝ͱͷ Contributors ϩʔυΛฒྻԽ

Slide 31

Slide 31 text

Future val future = loadContributorsConcurrentAsync(req) updateCancelFuture(future) future.thenAccept { users -> SwingUtilities.invokeLater { updateResults(users) } } fun loadContributorsConcurrentAsync( req: RequestData ): CompletableFuture> = GlobalScope.future { loadContributorsConcurrent(req) }

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Gather suspend fun loadContributorsGather( req: RequestData, callback: suspend (List) -> Unit ) = coroutineScope { val service = createGitHubService(req.username, req.password) val repos = service.listOrgRepos(req.org).await() val channel = Channel>() for (repo in repos) { launch { val users = service.listRepoContributors(req.org, repo.name).await() channel.send(users) } } var contribs = emptyList() repeat(repos.size) { val users = channel.receive() contribs = (contribs + users).aggregateSlow() callback(contribs) } } Channel Λ࢖༻

Slide 35

Slide 35 text

Actor suspend fun loadContributorsActor( req: RequestData, uiUpdateActor: SendChannel> ) = coroutineScope { val service = createGitHubService(req.username, req.password) val repos = service.listOrgRepos(req.org).await() val aggregator = aggregatorActor(uiUpdateActor) val requests = Channel() val workers = List(4) { workerJob(requests, aggregator) } for (repo in repos) { requests.send(WorkerRequest(service, req.org, repo.name)) } requests.close() workers.joinAll() aggregator.close() } List → requests : Channel → aggregator: SendChannel> → uiUpdateActor : SendChannel> 4ฒྻͰWorkRequestΛॲཧ

Slide 36

Slide 36 text

fun CoroutineScope.aggregatorActor( uiUpdateActor: SendChannel> ) = actor> { var contribs: List = emptyList() // STATE for (users in channel) { contribs = (contribs + users).aggregateSlow() uiUpdateActor.send(contribs) } } class WorkerRequest( val service: GitHubService, val org: String, val repo: String ) fun CoroutineScope.workerJob( requests: ReceiveChannel, aggregator: SendChannel> ) = launch { for (req in requests) { val users = req.service.listRepoContributors(req.org, req.repo).await() log.info("${req.repo}: loaded ${users.size} contributors") aggregator.send(users) } } actor { } Λ࢖༻

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

Have a Nice Kotlin! • blog : Y.A.M ͷࡶهா • y-anz-m.blogspot.com • twitter : @yanzm ʢ΍Μ͟Ήʣ • uPhyca Inc. (גࣜձࣾ΢ϑΟΧ)