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
290
Coroutine Kyuin
社内勉強会「冬休み前にKotlinのCoroutinesを吸引したい人が集う会」資料
uzzu
December 20, 2018
Tweet
Share
More Decks by uzzu
See All by uzzu
Context Receiversに思いを馳せる / Context Receivers
uzzu
0
700
StoreKitのこれまでとこれから / StoreKit 2 from 1
uzzu
5
17k
Autofill Framework
uzzu
0
130
アプリ内課金の最新事情 クライアントサイド編 / In-app Purchase in Cookpad 2019
uzzu
3
4.5k
Billing Client 2.0 acknowledgement
uzzu
0
17k
Promoting IAP対応から学ぶ外部アプリ内課金実装 / Promoting IAP and others
uzzu
2
1.5k
ブログ作り直した / My blog @ Othlo Tech
uzzu
0
170
新規アプリ開発を支えるユーザ・決済基盤
uzzu
2
2.8k
kotlin-mpp-library-tips
uzzu
1
6.3k
Other Decks in Technology
See All in Technology
LLMエージェント時代に適応した開発フロー
hiragram
1
410
VPC Latticeのサービスエンドポイント機能を使用した複数VPCアクセス
duelist2020jp
0
240
Devinを使ったモバイルアプリ開発 / Mobile app development with Devin
yanzm
0
190
Goss: New Production-Ready Go Binding for Faiss #coefl_go_jp
bengo4com
0
1.1k
RAID6 を楔形文字で組んで現代人を怖がらせましょう(実装編)
mimifuwa
1
310
Browser
recruitengineers
PRO
4
330
7月のガバクラ利用料が高かったので調べてみた
techniczna
3
440
小さなチーム 大きな仕事 - 個人開発でAIをフル活用する
himaratsu
0
120
Gaze-LLE: Gaze Target Estimation via Large-Scale Learned Encoders
kzykmyzw
0
320
そのコンポーネント、サーバー?クライアント?App Router開発のモヤモヤを可視化する補助輪
makotot
4
550
.NET開発者のためのAzureの概要
tomokusaba
0
230
Yahoo!広告ビジネス基盤におけるバックエンド開発
lycorptech_jp
PRO
1
280
Featured
See All Featured
KATA
mclloyd
32
14k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.6k
Mobile First: as difficult as doing things right
swwweet
223
9.9k
Agile that works and the tools we love
rasmusluckow
329
21k
Statistics for Hackers
jakevdp
799
220k
Designing Experiences People Love
moore
142
24k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
For a Future-Friendly Web
brad_frost
179
9.9k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Docker and Python
trallard
45
3.5k
Optimizing for Happiness
mojombo
379
70k
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ؔ࿈