Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Shallow Dip into Kotlin Coroutine
Search
bigbackboom
April 17, 2024
Technology
270
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Shallow Dip into Kotlin Coroutine
bigbackboom
April 17, 2024
More Decks by bigbackboom
See All by bigbackboom
Learn as a Pair
bigbackboom
0
75
Not 2 L8 JKでもわかるMaterial 3
bigbackboom
0
62
JKでもわかるSFace Recognition
bigbackboom
0
82
Androidタブレットアプリ作成_棚から牡丹餅を得るにはまず棚から
bigbackboom
0
70
Proto Datastoreを使う前の心構え
bigbackboom
0
330
Extended A Study in Bitmap: Is NDK the fast Processing method by CPU?
bigbackboom
0
35
Have A Dog in CircleCI
bigbackboom
0
94
Androidエンジニアのお仕事でのショボーン
bigbackboom
0
97
解明!楽しいプレゼンする話すスキル
bigbackboom
0
130
Other Decks in Technology
See All in Technology
AI時代こそ、スケールしないことをしよう -「作る人」から「なぜ作るか」を考える人へ / Do Things That Don't Scale in the AI Era — From How to Why
kaminashi
1
150
Claude Mythos、Fable...フロンティアAIの最新動向と企業のセキュリティ対策
flatt_security
0
150
2026年のソフトウェア開発を考える(2026/07版) / Agentic Software Engineering 2026-07 Findy Edition
twada
PRO
29
16k
変更し続けられるシステムをどう保つか — AI時代のSSoTという設計原則
kawauso
1
1.3k
AIが当たり前の組織で エンジニアはどう育つか
nishihira
1
1.3k
AI Agent を本番環境へ―― Microsoft Foundry × Azure Serverless で作る Enterprise-Ready な基盤
shibayan
PRO
1
510
データ活用研修 問いの発見と仮説構築【MIXI 26新卒技術研修】
mixi_engineers
PRO
1
310
AIエージェントがあれば技術書なんてすぐ書けるでしょ→無理でした
watany
5
480
CTOキーノート:AI時代の「つなぐ」を再定義 ― 真のIoTとリアルワールドAI【SORACOM Discovery 2026】
soracom
PRO
0
130
AI研修(Day2)【MIXI 26新卒技術研修】
mixi_engineers
PRO
1
740
副作用のある Lambda でも Lambda Power Tuning は使えるのか / lambda-power-tuning-side-effects
koukihosaka
2
150
歴史から理解するクラウドインフラのしくみ
kizawa2020
0
160
Featured
See All Featured
Game over? The fight for quality and originality in the time of robots
wayneb77
1
230
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.4k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
280
ラッコキーワード サービス紹介資料
rakko
1
4M
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
64
56k
WCS-LA-2024
lcolladotor
0
760
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
320
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
430
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Skip the Path - Find Your Career Trail
mkilby
1
170
Transcript
Shallow Dip into Kotlin Coroutine キクチコウダイ
自己紹介 菊池 広大(キクチコウダイ) 2023年6月 株式会社マネーフォワードに入社 埼玉出身、香港育ち、 Iターンで東京から福岡に引越し Github: https://github.com/BigBackBoom
発表の概要
Coroutineとは Coroutineが スレッドの並列処理とどう違うのか、 Kotlinをベースに説明します。
Coroutineとは
Coroutineとは サブルーチンを並列処理させるために 一般化した手法
Coroutineとは • もともとは1963年にCobolのコンパイラ周りで提唱された • 複数のサブルーチンが自分の処理を中断し、プロセス間で リソースの協力をしながら並列処理を実行する。
Coroutineとは
Coroutineとは 普通のサブルーチン(メソッド)とは違うの? a. サブルーチンは呼び出されるたびに、一から処理が開 始される b. Coroutineはサブルーチンで処理を中断して、別の処 理の開始・再開ができる
Coroutineとは スレッド使えば十分じゃない? • スレッドはOS管理されている。そのため、OS毎に実装 を変更・バイナリの再コンパイルする必要がある。 • また、スレッドを複数立ち上げると、ハードウェアリソー スも大量に消費する。
Kotlin Coroutineの使い方
Launch Lauchを呼び出すことでCoroutineの非同期 処理を開始できる fun main(args: Array<String>) { GlobalScope.launch { println("world")
} println("Hello") // 結果 // Hello } Launch
Launch • Launch処理が始まる前にmainが終 わってしまうので変更 • runBlockingは通常コードとCoroutine をブリッジするために使われる • Globalscopeを直接指定するのは、 Warningが出るので注意
fun main(args: Array<String>) { runBlocking { launch { println("Hello") } } println("World") // Hello // World } Launch
Launch • Coroutine内でサブルーチンを呼び出 す • サブルーチンの定義にsuspendをつけ る • サブルーチンの呼び出しで処理の中断 が行われる
suspend fun printWorld() { delay(1000) // 中断 println("world") } fun main(args: Array<String>) { runBlocking { launch { printWorld() // 中断 } println("Hello") } // Hello // 〜1秒休憩〜 // World } } Suspend
Coroutineの実現方法
Coroutineの実現方法 Coroutineの処理はコンパイル時に ステートマシンコードが生成され置き換えられる。 単純にメソッドが実行されるわけではない
ステートマシン 右のコードをJVMバイトコードからデコンパイ ルして、中身を確認しました suspend fun printWorld() { delay(1000) // 中断
println("world") } fun main(args: Array<String>) { runBlocking { launch { printWorld() // 中断 } println("Hello") // Hello // World }
ステートマシン デコンパイルした中身を擬似コード化 1. mainのLaunchの中身が実行される fun printWorld(continue: Continuation) { val cont
= ContinuationImpl() { fun invokeSuspend() { printWorld() } } switch(continue.label){ 0: label = 1 if(Delayed(1000, cont) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } println(“world") } // EventLoop // Default label = 0 fun main() { runBlocking { launch { switch(label){ 0: label = 1 if(printWorld(this) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } } println("Hello") } }
ステートマシン デコンパイルした中身を擬似コード化 1. mainのLaunchの中身が実行される 2. 非同期なので、Helloがコンソールに表 示 fun printWorld(continue: Continuation)
{ val cont = ContinuationImpl() { fun invokeSuspend() { printWorld(this) } } switch(continue.label){ 0: label = 1 if(Delayed(1000, cont) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } println(“world") } // EventLoop // Default label = 0 fun main() { runBlocking { launch { switch(label){ 0: label = 1 if(printWorld(this) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } } println("Hello") } }
ステートマシン 3. launchのlabelの0が実行され、 printWorldのメソッドが動く fun printWorld(continue: Continuation) { val cont
= ContinuationImpl() { fun invokeSuspend() { printWorld(this) } } switch(continue.label){ 0: label = 1 if(Delayed(1000, cont) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } println(“world") } // EventLoop // Default label = 0 fun main() { runBlocking { launch { switch(label){ 0: label = 1 if(printWorld(this) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } } println("Hello") } }
ステートマシン 3. launchのlabelの0が実行され、 printWorldのメソッドが動く 4. printWorldでDelayedが走り、 printWorldを再開先として、 ContinuationImplを渡す。 fun printWorld(continue:
Continuation) { val cont = ContinuationImpl() { fun invokeSuspend() { printWorld(this) } } switch(continue.label){ 0: label = 1 if(Delayed(1000, cont) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } println(“world") } // EventLoop // Default label = 0 fun main() { runBlocking { launch { switch(label){ 0: label = 1 if(printWorld(this) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } } println("Hello") } }
ステートマシン 3. launchのlabelの0が実行され、 printWorldのメソッドが動く 4. printWorldでDelayedが走り、 printWorldを再開先として、 ContinuationImplを渡す。 5. returnされて一旦全体の処理が終了す
る。 fun printWorld(continue: Continuation) { val cont = ContinuationImpl() { fun invokeSuspend() { printWorld(this) } } switch(continue.label){ 0: label = 1 if(Delayed(1000, cont) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } println(“world") } // EventLoop // Default label = 0 fun main() { runBlocking { launch { switch(label){ 0: label = 1 if(printWorld(this) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } } println("Hello") } }
ステートマシン 3. launchのlabelの0が実行され、 printWorldのメソッドが動く 4. printWorldでDelayedが走り、 printWorldを再開先として、 ContinuationImplを渡す。 5. returnされて一旦全体の処理が終了す
る。 6. 1秒経つと、ContinuationImplの invokeSuspendが実行され、再度 printWorldを実行。 fun printWorld(continue: Continuation) { val cont = ContinuationImpl() { fun invokeSuspend() { printWorld(this) } } switch(continue.label){ 0: label = 1 if(Delayed(1000, cont) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } println(“world") } // EventLoop // Default label = 0 fun main() { runBlocking { launch { switch(label){ 0: label = 1 if(printWorld(this) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } } println("Hello") } }
ステートマシン 7. 二度目では、ラベルがマイナスに更新さ れているため、Worldがコンソールに表 示 fun printWorld(continue: Continuation) { val
cont = ContinuationImpl() { fun invokeSuspend() { printWorld(this) } } switch(continue.label){ 0: label = 1 if(Delayed(1000, cont) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } println(“world") } // EventLoop // Default label = 0 fun main() { runBlocking { launch { switch(label){ 0: label = 1 if(printWorld(this) == suspend) return suspend break; 1: throwOnFailure 2: ThrowIllegalState } } println("Hello") } }
Coroutineの実現方法 中断の原理はステートマシンだったとして 並列処理はなんでできるの?
Coroutineの実現方法 Coroutineの実行周りは三つのクラスに分かれる • Job:launch, async, flowなどのたびに作成される。 • Worker:スレッドそのもの、Jobを実行する。 • Scheduler:Workerを管理する。リソース管理を行う
Coroutineの実現方法
Coroutineの実現方法 • 並列処理自体は、スレッドにて実現 • 一つのスレッドが複数の処理を実行するので、処理ご とにスレッドを立ち上げるよりオーバーヘッドが少ない • そのため、大量のスレッドを立ち上げるより軽量に動け る
Coroutineの実現方法 • そのほかにも、JobがJobを作成していた場合の親子 関係や、実行できるスレッドのScopeやContextなどの 考えがある
Kotlin/Nativeの謎
Kotlin/Nativeの謎 Native周りのコードにlauchなどが見当たらない。
Kotlin/Nativeの謎 Kotlin → LLVM中間コードの コンパイラが見つからないので、 まさか直に置き換えている?🤔
Kotlin/Nativeの謎 それ以外の、Worker/Jobの概念は一緒。 Objective-C++で書かれているので、 iOS/Linuxなど複数プラットフォームをこれで対応して いる?
まとめ
Coroutineとは • Coroutineは古くからある手法で、プログラミング言語の実 装として実現されている • そのため、少ないリソースで非同期処理を実現している • また、プログラミング言語さえ動けばOS環境は不問 • Kotlinでは、JVMのスレッド処理とステートマシンによって
非同期な処理を実現している。
以上、ありがとうございました!
参考資料 • Asynchronous Programming with coroutines