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
Coroutine Kyuin
Search
uzzu
December 20, 2018
Technology
2
280
Coroutine Kyuin
社内勉強会「冬休み前にKotlinのCoroutinesを吸引したい人が集う会」資料
uzzu
December 20, 2018
Tweet
Share
More Decks by uzzu
See All by uzzu
Context Receiversに思いを馳せる / Context Receivers
uzzu
0
660
StoreKitのこれまでとこれから / StoreKit 2 from 1
uzzu
5
15k
Autofill Framework
uzzu
0
110
アプリ内課金の最新事情 クライアントサイド編 / In-app Purchase in Cookpad 2019
uzzu
3
4.4k
Billing Client 2.0 acknowledgement
uzzu
0
17k
Promoting IAP対応から学ぶ外部アプリ内課金実装 / Promoting IAP and others
uzzu
2
1.4k
ブログ作り直した / My blog @ Othlo Tech
uzzu
0
150
新規アプリ開発を支えるユーザ・決済基盤
uzzu
2
2.7k
kotlin-mpp-library-tips
uzzu
1
6.3k
Other Decks in Technology
See All in Technology
newmo の創業を支える Software Architecture と Platform Engineering
110y
5
460
本当に必要なのは「QAという技術」だった!試行錯誤から生まれた、品質とデリバリーの両取りアプローチ / Turns Out, "QA as a Discipline" Was the Key!
ar_tama
9
4.3k
Асинхронная коммуникация в Go: от понятного к душному. Дима Некрасов, Otello, 2ГИС
lamodatech
0
2.1k
Previewでもここまで追える! Azure AI Foundryで始めるLLMトレース
tomodo_ysys
2
640
Pythonデータ分析実践試験 出題傾向や学習のポイントとテクニカルハイライト
terapyon
1
140
名単体テスト 禁断の傀儡(モック)
iwamot
PRO
1
140
LINE 購物幕後推手
line_developers_tw
PRO
0
430
経済メディア編集部の実務に小さく刺さるAI / small-ai-with-editorial
nkzn
2
330
10分で学ぶ、RAGの仕組みと実践
supermarimobros
0
920
genspark_presentation.pdf
haruki_uiru
1
240
Cursorを全エンジニアに配布 その先に見据えるAI駆動開発の未来 / 2025-05-13-forkwell-ai-study-1-cursor-at-loglass
itohiro73
2
470
Google Cloud Next 2025 Recap アプリケーション開発を加速する機能アップデート / Application development-related features of Google Cloud
ryokotmng
0
130
Featured
See All Featured
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
14
1.5k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
19
1.2k
The Language of Interfaces
destraynor
158
25k
[RailsConf 2023] Rails as a piece of cake
palkan
54
5.5k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.7k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
GraphQLの誤解/rethinking-graphql
sonatard
71
10k
How to Think Like a Performance Engineer
csswizardry
23
1.6k
Six Lessons from altMBA
skipperchong
28
3.8k
KATA
mclloyd
29
14k
Transcript
ౙٳΈલʹ ,PUMJOͷ$PSPVUJOFTΛ ٵҾ͍ͨ͠ਓ͕ू͏ձ !V[[V
झࢫ w,PUMJOͰՌग़ͧ͢ w·ͩ$PSPVUJOFTΑ͔ͬͯ͘ͳ͍ͧ w$PSPVUJOFTରԠਓࡐʹͳΔͧ
ຊ w ,PUMJOϕʔεͰ͠·͢ w$PSPVUJOFTͱ wଞݴޠʹ͓͚ΔBTZODBXBJUͱͷҧ͍ w͍ํͬ͘͟Γ wͱΓ͜ΕϦϯΫू
$PSPVUJOFT w,PUMJO͔Βਖ਼ࣜϦϦʔε͞Εͨඇಉظϓϩάϥ ϛϯάͷҝͷػೳ ͪΖΜNVMUJQMBUGPSNରԠ wଞݴޠͰ͍͏ॴͷBTZODBXBJUؚ͕·Ε͍ͯΔ wଞݴޠͰ͍͏ॴͷDPSPVUJOF HFOFSBUPS ,PUMJOͰ4FRVFODF5
BTZODBXBJU $ class Program { static async ValueTask<int> DoSomething(int value)
{ await Task.Delay(1000); return value * value; } static async Task MainAsync(string[] args) { Console.WriteLine("Start task"); var result = await DoSomething(100); Console.WriteLine($"Result: {result}"); } static void Main(string[] args) => MainAsync(args).Wait(); }
BTZODBXBJU $ class Program { static async ValueTask<int> DoSomething(int value)
{ await Task.Delay(1000); return value * value; } static async Task MainAsync(string[] args) { Console.WriteLine("Start task"); var result = await DoSomething(100); Console.WriteLine($"Result: {result}"); } static void Main(string[] args) => MainAsync(args).Wait(); }
BTZODBXBJU $ class Program { static async ValueTask<int> DoSomething(int value)
{ await Task.Delay(1000); return value * value; } static async Task MainAsync(string[] args) { Console.WriteLine("Start task"); var result = await DoSomething(100); Console.WriteLine($"Result: {result}"); } static void Main(string[] args) => MainAsync(args).Wait(); }
BTZODBXBJU &4 function sleep(milliSeconds) { return new Promise(resolve => setTimeout(resolve,
milliSeconds)); } async function doSomething(value) { await sleep(1000); return value * value; } (async() => { console.log("Start task."); const result = await doSomething(100); console.log(`Result: ${result}`) })();
BTZODBXBJU &4 function sleep(milliSeconds) { return new Promise(resolve => setTimeout(resolve,
milliSeconds)); } async function doSomething(value) { await sleep(1000); return value * value; } (async() => { console.log("Start task."); const result = await doSomething(100); console.log(`Result: ${result}`) })();
BTZODBXBJU &4 function sleep(milliSeconds) { return new Promise(resolve => setTimeout(resolve,
milliSeconds)); } async function doSomething(value) { await sleep(1000); return value * value; } (async() => { console.log("Start task."); const result = await doSomething(100); console.log(`Result: ${result}`) })();
BTZODBXBJU wBTZODGVODUJPOΛ࣮ͯ͠ ݺͼग़͠ଆͰBXBJU͢Δ
$PSPVUJOFT suspend fun doSomething(value: Int): Int { delay(1000) return value
* value } fun main() = runBlocking { println("Start task") val result = doSomething(100) println("Result: $result") }
$PSPVUJOFT suspend fun doSomething(value: Int): Int { delay(1000) return value
* value } fun main() = runBlocking { println("Start task") val result = doSomething(100) println("Result: $result") }
$PSPVUJOFT suspend fun doSomething(value: Int): Int { delay(1000) return value
* value } fun main() = runBlocking { println("Start task") val result = doSomething(100) println("Result: $result") }
$PSPVUJOFT wTVTQFOEGVODUJPOΛ࣮ͯ͠ ݺͼग़͠ଆͨͩݺͿ BXBJULFZXPSEͳ͠ BTZODBXBJUͳݴޠͰඇಉظͰ͋Δࣄ͕લఏ ,PUMJOͰඇಉظؔͰͳ͘தஅؔͳͷͰ ɹಉظzతzʹهड़Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ ɹଞݴޠͷΑ͏ʹಉظඇಉظΛҙࣝ͢Δඞཁ͕ͳ͍
͍ํ w%FQFOEFODJFTͷՃ w$PSPVUJOF4DPQFΛ࣮͢Δ w$PSPVUJOF4DPQFMBVODIͯ͠ Α͠ͳʹTVTQFOEGVODUJPOΛݺͼग़͢
%FQFOEFODJFTͷՃ w,PUMJOdΛೖΕΔ͚ͩͰ࣮࣭͑ͳ͍ ݴޠͱͯ͠ϨΠϠʔͳ༷ͷΈಉ͍ࠝͯ͠Δҝ wՃ͑ͯɺ1MBUGPSNʹ߹ΘͤͯϥΠϒϥϦΛՃ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1"
$PSPVUJOF4DPQFΛ࣮͢Δ wTVTQFOEGVODUJPO$PSPVUJOFͷத͋Δ͍ TVTQFOEGVODUJPO͔ΒͷΈར༻Ͱ͖Δ w$PSPVUJOF$PSPVUJOF4DPQFͷதͰͷΈ ىಈͰ͖Δ w$PSPVUJOF4DPQFͷ࣮͕ඞཁ
$PSPVUJOF4DPQFΛ࣮͢Δ suspend fun doSomething(value: Int): Int { delay(1000) return value
* value } fun main() = runBlocking { println("Start task") val result = doSomething(100) println("Result: $result") } ݱࡏͷ࣮ߦεϨουΛݩʹ CoroutineScopeΛ࡞ͬͯ ࣮ߦྃ·ͰͬͯΔ
$PSPVUJOF4DPQFΛ࣮͢Δ w࣮ͷલʹগ͚ͩ͠ొਓͷཧ ਂೖΓ͢ΔͱऴΘΒͳ͍ͷͰগ͚ͩ͠
࣮͢Δ্Ͱ࠷ݶͷొਓ w$PSPVUJOF$POUFYUϓϩύςΟͱͯ࣋ͭ͠ඞཁ͕͋Δ w+PCMBVODI͢Δ$PSPVUJOFͷϥΠϑαΠΫϧΛཧ w$PSPVUJOF%JTQBUDIFS࣮ߦίϯςΩετ 5ISFBEFUD wଞɺ$PSPVUJOF&YDFQUJPO)BOEMFS͍Δ ͕Ұ୴์ஔ
$PSPVUJOF4DPQFΛ࣮͢Δ class SimpleCoroutineScope(ui: CoroutineDispatcher) : CoroutineScope { // JobΛ࡞Δ(࡞Ε) private
val job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠ // JobjobϓϩύςΟͷͭ // ࣮ߦίϯςΩετίϯετϥΫλҾuiΛ༻͍Δ override val coroutineContext: CoroutineContext = job + ui }
$PSPVUJOF4DPQFΛ࣮͢Δ class SimpleCoroutineScope : CoroutineScope { // JobΛ࡞Δ(࡞Ε) private val
job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠ // JobjobϓϩύςΟͷͭ // ࣮ߦίϯςΩετmainϧʔϓΛ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.Main }
$PSPVUJOF4DPQFΛ࣮͢Δ class SimpleCoroutineScope : CoroutineScope { // JobΛ࡞Δ(࡞Ε) private val
job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠ // JobjobϓϩύςΟͷͭ // ࣮ߦίϯςΩετIO Pool(※ThreadͱݶΒͳ͍)Λ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.IO }
$PSPVUJOF4DPQFMBVODI͢Δ w جຊతͳॴͱͯ͠ MBVODI͢Δͱ$PSPVUJOF͕ى ಈ͢Δ $PSPVUJOF࣮ࡍ͍ΖΜͳॴͰىಈ͍ͯ͠Δ͚Ͳলུ wMBVODIͷલʹొਓΛʜ
ొਓ w$PSPVUJOF4DPQF͖ͬ͞࡞ͬͨͭ w$PSPVUJOF$POUFYU͖ͬ͞ϓϩύςΟʹ࣋ͨͤͨͭ w$PSPVUJOFMBVODIʹΑͬͯ࡞ΒΕΔ࣮ࡍʹಈ͍ͯΔͭ w+PC ུ %JTQBUDIFS FUDʜ͖ͬ͞આ໌ͨͭ͠ wଞɺ$PSPVUJOF4UBSU͋Δ͕Ұ୴লུ
$PSPVUJOF4DPQFMBVODI͢Δ class SimpleCoroutineScope : CoroutineScope { // JobΛ࡞Δ(࡞Ε) private val
job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠ // JobjobϓϩύςΟͷͭ // ࣮ߦίϯςΩετmainϧʔϓΛ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.Main }
$PSPVUJOF4DPQFMBVODI͢Δ class SimpleCoroutineScope : CoroutineScope { private val job: Job
= Job() override val coroutineContext: CoroutineContext = job + Dispatchers.Main fun foo() { launch { // Λjob // ࣮ߦίϯςΩετΛmainϧʔϓͱͯ͠ // CoroutineΛىಈ͠ॲཧΛ࣮ߦ͢Δ val result = doSomething() } } }
$PSPVUJOF4DPQFMBVODI͢Δ class SimpleCoroutineScope : CoroutineScope { // JobΛ࡞Δ(࡞Ε) private val
job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠ // JobjobϓϩύςΟͷͭ // ࣮ߦίϯςΩετIO Pool(※ThreadͱݶΒͳ͍)Λ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.IO }
$PSPVUJOF4DPQFMBVODI͢Δ class SimpleCoroutineScope : CoroutineScope { private val job: Job
= Job() override val coroutineContext: CoroutineContext = job + Dispatchers.IO fun foo() { launch { // Λjob // ࣮ߦίϯςΩετΛIO Poolͱͯ͠ // CoroutineΛىಈ͠ॲཧΛ࣮ߦ͢Δ val result = doSomething() } } }
$PSPVUJOF4DPQFMBVODI͢Δ wิɿ͜ΕDPNQJMFFSSPS SFUVSOͰ͖ͳ͍ fun execute(): Int { launch { return
doSomething() } }
TVTQFOEGVODUJPOΛ࣮͢Δ suspend fun doSomething(value: Int): Int { delay(1000) return value
* value } fun main() = runBlocking { println("Start task") val result = doSomething(100) println("Result: $result") }
TVTQFOEGVODUJPOΛ࣮͢Δ suspend fun doSomething(value: Int): Int { delay(1000) return value
* value } fun main() = runBlocking { println("Start task") val result = doSomething(100) println("Result: $result") } ͜Εsuspend function
TVTQFOEGVODUJPOΛ࣮͢Δ function sleep(milliSeconds) { return new Promise(resolve => setTimeout(resolve, milliSeconds));
} async function doSomething(value) { await sleep(1000); return value * value; } (async() => { console.log("Start task."); const result = await doSomething(100); console.log(`Result: ${result}`) })();
TVTQFOEGVODUJPOΛ࣮͢Δ function sleep(milliSeconds) { return new Promise(resolve => setTimeout(resolve, milliSeconds));
} async function doSomething(value) { await sleep(1000); return value * value; } (async() => { console.log("Start task."); const result = await doSomething(100); console.log(`Result: ${result}`) })(); ԞͰ͜Ε૬ͷͳʹ͔Λ ࣮͢Δඞཁ͕͋Δ
TVTQFOEGVODUJPOΛ࣮͢Δ w࣮ͷલʹొਓΛʜ
TVTQFOEGVODUJPOΛ࣮͢Δ wTVTQFOE$PSPVUJOFTVTQFOEGVODUJPOΛ࣮͢Δҝͷ ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ#VJMEFSGVODUJPO w$POUJOVBUJPOTVTQFOEGVODUJPOΛ࠶։͢Δҝͷ&NJUUFSɹ wଞɺTVTQFOE $PSPVUJOFɺ $POUJOVBUJPO γϦʔζ͕͍͔ͭ͋͘Δ͚ͲҰ୴লུ
TVTQFOEGVODUJPOΛ࣮͢Δ suspend fun doSomething(value: Int): Int = suspendCoroutine { continuation
-> continuation.resume(value * value) } suspend fun doSomething(value: Int): Int = suspendCoroutine { continuation -> continuation.resumeWithException(Throwable()) }
طଘίʔυΛTVTQFOEGVO w$14 ͍ΘΏΔDBMMCBDLܗࣜ ͔ΒҠߦ͍ͨ͠߹ fun doSomethingAsync(value: Int, listener: Listener) {
if (value <= 0) { listener.onError(Throwable()) } else { listener.onSuccess(value) } } suspend fun doSomething(value: Int): Int = suspendCoroutine { doSomethingAsync(value, object : Listener { override fun onSuccess(value: Int) { it.resume(value) } override fun onError(e: Throwable) { it.resumeWithException(e) } }) }
طଘίʔυΛTVTQFOEGVO w3FBDUJWFd͔ΒҠߦ͍ͨ͠߹ม༻ϥΠϒϥϦΛ͏ ҎԼ3Y+BWBͷྫ fun doSomethingSingle(value: Int): Single<Int> = Single.just(value
* value) suspend fun doSomething(value: Int): Int = doSomethingSingle(value).await() implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:1.0.1"
ྫ֎र͍͍ͨ launch { try { val result = doSomething() }
catch (e: Throwable) { // } } launch { runCatching { doSomething() } // Result<T>͕ฦ٫͞ΕΔ .onSuccess { value -> } .onFailure { throwable -> } } ,PUMJO͔ΒՃͷSVO$BUDIJOHਪ
࣮ߦίϯςΩετม͍͑ͨ class SimpleCoroutineScope : CoroutineScope { private val job: Job
= Job() override val coroutineContext: CoroutineContext = job + Dispatchers.Main fun execute() { launch { // Main runCatching { // Main withContext(Dispatchers.IO) { // IO doSomething() } } .onSuccess { value -> // Main } .onFailure { throwable -> // Main } } } }
Ωϟϯηϧ͍ͨ͠ $ static async ValueTask<int> DoSomething(int value, CancellationToken token) {
await Task.Delay(1000); token.ThrowIfCancellationRequested(); return value * value; } static async Task MainAsync(string[] args) { Console.WriteLine("Start task"); var cancellable = new CancellationTokenSource(); var task = DoSomething(100, cancellable.Token); cancellable.Cancel(); var result = await task; Console.WriteLine($"result: {result}"); }
Ωϟϯηϧ͍ͨ͠ &4 async function doSomething(value, token) { await sleep(1000); await
token.rejectIfCancelled(); return value * value; } (async() => { const cancellable = new Cancellable(); const finalize = () => cancellable.cancel(); process.on('exit', finalize); console.log("Start task."); doSomething(100, cancellable.token); console.log(`Result: ${result}`); process.removeListener('exit', finalize); })(); Cancellable.js https://gist.github.com/uzzu/7d6e89fafc4bcde1c6f6d82a3d164409 ˢྫ͕ѱ͍͕OPEFͰϓϩηεؒ௨৴ͭͭ͠ظλεΫ࣮ߦͯͯ͠ʜͳ࣌ͱ͔
Ωϟϯηϧ͍ͨ͠ class SimpleCoroutineScope : CoroutineScope { private val job: Job
= Job() override val coroutineContext: CoroutineContext = job + Dispatchers.Main fun onDestroy() { job.cancel() } }
Ωϟϯηϧ͍ͨ͠ class SimpleCoroutineScope : CoroutineScope { private val job: Job
= Job() override val coroutineContext: CoroutineContext = job + Dispatchers.Main fun onDestroy() { job.cancel() } } ࢠͷJob(Coroutine)͕શ෦cancel͞ΕΔ ݸผʹcancel͍ͨ͠έʔεʹ͍ͭͯলུ
ͱΓ͜ΕϦϯΫू w$PSPVUJOF(VJEF IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFTCMPC NBTUFSDPSPVUJOFTHVJEFNE ຊޠ༁IUUQTHJUIVCDPNQMKQLPUMJOYDPSPVUJOFTCMPC KBQBOFTF@USBOTMBUJPODPSPVUJOFTHVJEFNE w,PUMJO$POGͰࢀՃͨ͠XPSLTIPQ IUUQTHJUIVCDPNFMJ[BSPW$PSPVUJOFT8PSLTIPQ ຊʹॳาతͳॴ͔Β"DUPS 1SPEVDFS·Ͱ͔Δ
Ұ୴͜͜·Ͱ
ଞτϐοΫฉ͖͍ͨࣄ͋Εޙ΄ͲͲ͏ͧ w "EWBODFE 3Y+BWBΛར༻࣮ͨ͠ͱͷൺֱΛͯ͠ΈΑ͏ TVTQFOEGVODUJPOΛෳΒ͍ͤͨBTZODͷར༻ํ๏ͱҙ +BWBίʔυͱͷ૬ޓӡ༻ .VUFY ଟॏݺͼग़͠ࢭIPUMBVODI IPUTVTQFOEGVODUJPO ໋໊ద
6OJU5FTUͷॻ͖ํ $PSPVUJOF4UBSU $PSPVUJOF&YDFQUJPO)BOEMFS TVTQFOE$PSPVUJOF$POUJOVBUJPOγϦʔζ ଞඈౕͨ͠ $IBOOFM "DUPS 1SPEVDFS w %FFQ%JWJOH KPC EJTQBUDIFS ʜ ͬͯԿ ͲΜͳίʔυʹͳΔͷόΠτίʔυݟͳ͕Β $PSPVUJOFͷதͲ͏ͳͬͯΜͷιʔείʔυಡΈͳ͕Β NVMUJQMBUGPSNؔ࿈