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
710
StoreKitのこれまでとこれから / StoreKit 2 from 1
uzzu
5
18k
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.4k
Other Decks in Technology
See All in Technology
Geospatialの世界最前線を探る [2025年版]
dayjournal
1
220
神回のメカニズムと再現方法/Mechanisms and Playbook for Kamikai scrumat2025
moriyuya
4
740
AIツールでどこまでデザインを忠実に実装できるのか
oikon48
6
3.3k
from Sakichi Toyoda to Agile
kawaguti
PRO
1
120
社内報はAIにやらせよう / Let AI handle the company newsletter
saka2jp
8
1.4k
JAZUG 15周年記念 × JAT「AI Agent開発者必見:"今"のOracle技術で拡張するAzure × OCIの共存アーキテクチャ」
shisyu_gaku
1
160
なぜAWSを活かしきれないのか?技術と組織への処方箋
nrinetcom
PRO
4
820
Codexとも仲良く。CodeRabbit CLIの紹介
moongift
PRO
0
200
カンファレンスに託児サポートがあるということ / Having Childcare Support at Conferences
nobu09
1
540
ニッポンの人に知ってもらいたいGISスポット
sakaik
0
130
やる気のない自分との向き合い方/How to Deal with Your Unmotivated Self
sanogemaru
0
500
AWS Top Engineer、浮いてませんか? / As an AWS Top Engineer, Are You Out of Place?
yuj1osm
2
210
Featured
See All Featured
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.5k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
Typedesign – Prime Four
hannesfritz
42
2.8k
Making Projects Easy
brettharned
119
6.4k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.2k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
46
7.7k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
Being A Developer After 40
akosma
91
590k
The World Runs on Bad Software
bkeepers
PRO
72
11k
GraphQLとの向き合い方2022年版
quramy
49
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ؔ࿈