Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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
81
Not 2 L8 JKでもわかるMaterial 3
bigbackboom
0
70
JKでもわかるSFace Recognition
bigbackboom
0
92
Androidタブレットアプリ作成_棚から牡丹餅を得るにはまず棚から
bigbackboom
0
73
Proto Datastoreを使う前の心構え
bigbackboom
0
340
Extended A Study in Bitmap: Is NDK the fast Processing method by CPU?
bigbackboom
0
43
Have A Dog in CircleCI
bigbackboom
0
100
Androidエンジニアのお仕事でのショボーン
bigbackboom
0
100
解明!楽しいプレゼンする話すスキル
bigbackboom
0
140
Other Decks in Technology
See All in Technology
ソフトウェアDNAとクラウドエージェントのススメ
cloudace
0
120
その Lambda、8分で 管理者権限まで奪われます
k1nakayama
7
3.6k
[Kiro Meetup #7] Kiro Crew Dive Deep
konippi
0
250
研究開発部の紹介 / Sansan R&D Profile
sansan33
PRO
5
25k
SREの視点で考えるSIEM活用術 〜AWS環境でのセキュリティ強化〜
cscengineer
PRO
0
280
手を動かして実感する、Kiro が変える開発体験
inariku
0
190
データ_AIの事業の勝敗をわけるもの
nek0128
1
480
Von-Neumann Machines, Dreams & The Futures of IT
ufried
0
120
AI de Idea
kawaguti
PRO
2
130
.NET WebAssemblyで実現するクライアントサイドAI推論:NuGetからViteまで、2つのエコシステムを繋ぐビルド戦略
yamachu
1
590
リアーキテクチャ後の障害ゼロを目指したShadow Testingの取り組み
nihonbuson
PRO
1
170
データ界隈LT祭 第1回LT登壇
taromatsui_cccmkhd
2
1.5k
Featured
See All Featured
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
12k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
76k
Building the Perfect Custom Keyboard
takai
2
880
Deep Space Network (abreviated)
tonyrice
0
320
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
990
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
Discover your Explorer Soul
emna__ayadi
2
1.3k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
700
GitHub's CSS Performance
jonrohan
1033
470k
How STYLIGHT went responsive
nonsquared
100
6.3k
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