Kotlin Coroutines の基本や仕組みの話です。 Android での話を中心にしてますが、Kotlinが動く環境ならほぼ同じなので、Android以外のKotlin開発者の方も参考になるかと思います。
2019/11/30 Android 研究&発表会登壇資料 https://arap.connpass.com/event/153097/ #arap_osaka
Kotlin Coroutines͜ͱ͡Ί
View Slide
ࣗݾհ•w ழມॆԝ ͍ͷ·ͨΈͭͻΖw ᷂UFDIWFJOදɻ J04"OESPJEεϚϗΞϓϦΤϯδχΞɻ 3Y͕͖Ͱ͢ɻw QSJWBUFUXJUUFS!JOP
ࠓͷ• KotlinίϧʔνϯͷجຊͱΈΛΖ͏
ҰൠతʹɺCoroutine ͱ• தஅɾ࠶։͕Մೳͳαϒϧʔνϯ• ฒߦੑ(Concurrent)Λఏڙ͢Δ
αϒϧʔνϯʹී௨ͷؔ(ͳͲ)αϒϧʔνϯؔͳͲॲཧॲཧॲཧʜSFUVSOl)FMMP 8PSMElϝΠϯॲཧαϒϧʔνϯ։࢝ʜαϒϧʔνϯऴྃ
ίϧʔνϯʹதஅՄೳͳαϒϧʔνϯίϧʔνϯॲཧZJFMElIFMMPzॲཧZJFMElXPSMEzॲཧʜϝΠϯॲཧίϧʔνϯ։࢝ʜίϧʔνϯऴྃ
ίϧʔνϯฒߦ(Concurrent)ʹಈ࡞͢ΔεϨου"ίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯεϨου#ίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯ
ฒߦ(Concurrent) ͱ ฒྻ(Parallel)• ฒߦ(Concurrent) ͷྫ: Coroutine• ฒྻ(Parallel) ͷྫ: ϚϧνεϨουɾϚϧνϓϩηε
ฒߦ(Concurrent) != ฒྻ(Parallel)εϨου"ίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯ͜ΕฒߦͰ͋ͬͯ ฒྻͰͳ͍͜ΕฒߦͰ ฒྻͰ͋ΔεϨου#εϨου"ίϧʔνϯ ίϧʔνϯ
Coroutines are light-weight.
Kotlin Coroutines
Kotlin Coroutine ͷΩϞ• Suspending Function• Structured concurrency• CoroutineContext• Async as Sync
Kotlin CoroutineͷΩϞᶃ Suspending Function
Suspending Function• Kotlin Coroutines ɺίϧʔνϯͷதஅͰ͖Δੑ࣭Λ suspend ؔ(SuspendingFunction)Ͱ࣮ݱ͍ͯ͠Δɻ
Suspending Function ͷੑ࣭• suspend ؔଞͷ suspend ؔͷதͰ͔࣮͠ߦͰ͖ͳ͍ɻ• ࢠͷ suspend ͕ؔதஅ͢Δͱɺͷsuspend ؔࢭ·Δɻ• suspend ؔͷதͰී௨ͷؔ(suspendͰͳ͍ؔ)ΛݺͿ͜ͱͰ͖Δɻ
Hello world to Kotlin Coroutine
͜ͷαϯϓϧͰ͍ͬͯΔؔ• ίϧʔνϯϏϧμʔ(ੜؔ):• runBlocking { ... }• CoroutineScope#launch { ... }• suspendؔ: delay(timeMillis: Long)※: runBlockingཚ༻NGɻ ɹɹAndroidڥͰΘͳ͍͜ͱʂ
Android ൛
CoroutineScopeΫϥε• ίϧʔνϯͷੜଘظؒΛཧ͢ΔΦϒδΣΫτɻ• MainScope ... UIεϨουͰಈ࡞͢Δείʔϓɻ → AndroidͷActivity ͳͲͱඥ͚ͯը໘ͷ ɹϥΠϑαΠΫϧͱҰகͤ͞ΒΕΔɻ• GlobalScope ... ΞϓϦͷੜଘظؒͱಉ͡είʔϓɻ → όονॲཧͳͲɺΞϓϦੜଘதʹऴΘͬͯࠔΔॲཧΛ࣮ߦ͢Δɻ
αεϖϯυؔͷྫ• delay (timeMillis: Long) ... ࢦఆϛϦඵͭɻ• withTimeout(timeMillis: Long) { ... }withTimeoutOrNull(timeMillis: Long) { ...} ... ϒϩοΫͷॲཧ͕ࢦఆϛϦඵΛ͑ͨͱ͖ʹ ɹλΠϜΞτͤ͞Δɻ• yield() ... ॲཧΛॠஅͯ͠ɺ(͋Ε)ଞͷίϧʔνϯʹॲཧΛճ͢ɻ
suspend ϊϯϒϩοΩϯά• suspend = தஅ• ͚ͩͲɺεϨουΛϒϩοΫ͠ͳ͍• →εϨουΛϒϩοΫ͢Δྫ: Thread.sleep()
Coroutine ͷ suspend ؔॲཧΛதஅͯ͠ɺଞͷฒߦॲཧதͷίϧʔνϯʹεϨουΛৡΔɻεϨου"ίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯZJFME
εϨου"ίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯZJFME
εϨου"ίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯZJFMEZJFMEZJFME
Suspend Function ͰίϧʔνϯͷதஅͰ͖Δੑ࣭Λ࣮ݱ͍ͯ͠Δ
Kotlin CoroutineͷΩϞᶄ Structured Concurrency
Structured concurrencyฒߦੑͷߏԽ• ίϧʔνϯࢠؔΛ࣋ͯΔɻίϧʔνϯίϧʔνϯίϧʔνϯ ίϧʔνϯίϧʔνϯ
Α͋͘ΔϚϧνεϨουͳ ඇಉظॲཧͷ• Ұ෦ͷεϨουΛམͱͨ͠(མͪͨ)ͱ͖ʹɺ ΓͷεϨουΛڠௐͤ͞Δͷ͕େมɻ• λΠϛϯάͰσουϩοΫͨ͠Γɺҙਤ͠ͳ͍ڍಈ͕ى͜Γ͍͢ɻ• ͕ى͖ͨͱ͖ʹݪҼڀ໌ɾσόοά͕͍͠ɻ
ࢠؔͷ͋Δίϧʔνϯ ڠௐ͍ͤ͢͞
ࢠؔͷ͋Δίϧʔνϯ ڠௐ͍ͤ͢͞ίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯ ίϧʔνϯίϧʔνϯΞΫςΟϒͳίϧʔνϯ
ࢠڙͷऴྃΛͬͯऴྃ͢ΔΞΫςΟϒͳίϧʔνϯػதͷίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯίϧʔνϯ ίϧʔνϯίϧʔνϯ
ࢠؔͷ͋Δίϧʔνϯ ྫ֎ɾΩϟϯηϧ࣌ڠௐ͍ͤ͢͞
ࢠؔͷ͋Δίϧʔνϯ ྫ֎ɾΩϟϯηϧ࣌ڠௐ͍ͤ͢͞ίϧʔνϯίϧʔνϯίϧʔνϯ ίϧʔνϯίϧʔνϯྫ֎ൃੜʂ
ίϧʔνϯʹྫ֎Λͯ͠ ίϧʔνϯΛऴྃ͢Δίϧʔνϯίϧʔνϯίϧʔνϯ ίϧʔνϯίϧʔνϯྫ֎ൃੜʂྫ֎εϩʔྫ֎εϩʔ
ίϧʔνϯ͕ऴྃ͢Δ࣌ɺ ࢠίϧʔνϯΩϟϯηϧ͢Δίϧʔνϯίϧʔνϯίϧʔνϯ ίϧʔνϯίϧʔνϯྫ֎ൃੜʂKPCDBODFM KPCDBODFM
ʹίϧʔνϯΛࢭΊΕɺࢠίϧʔνϯࢭ·Δ
ࢠϧʔνϯͷείʔϓΛΩϟϯηϧ͢ΕɺࢠͱͲࢭΊΒΕΔ
ίϧʔνϯͷ࣮ߦείʔϓΛ Ωϟϯηϧ͢Δ͚ͩͰશ෦ࢭΊΒΕΔίϧʔνϯ.BJO4DPQFKPCDBODFM "DUJWJUZPO%FTUSPZ TDPQFDBODFM ίϧʔνϯKPCDBODFM
(࠶ܝ) Android Hello world
ίϧʔνϯͲ͏ͬͯࢠؔΛ࡞͍ͬͯΔͷ͔ʁ→ CoroutineScope
launch ͷϥϜμࣜ this = CoroutineScope
ίϧʔνϯ.BJO4DPQFKPCDBODFM "DUJWJUZPO%FTUSPZ TDPQFDBODFM ίϧʔνϯίϧʔνϯKPCDBODFM (MPCBM4DPQFGlobalScopeͷίϧʔνϯ.BJO4DPQFͱؔͳ͘ಈ͘ʂlaunch launchlaunch
Structured Concurrency Λ׆༻͢Είϧʔνϯཧָ͕ʹͳΔ
Kotlin CoroutineͷΩϞᶅ CoroutineContext
CoroutineContext%JTQBUDIFSɿ.BJO+PCɿͳ͠ϝΠϯείʔϓͷίϯςΩετ%JTQBUDIFSɿ.BJO+PCɿίϧʔνϯείʔϓ1ͷίϯςΩετ%JTQBUDIFSɿ.BJO+PCɿίϧʔνϯείʔϓͷίϯςΩετ%JTQBUDIFSɿ%FGBVMU+PCɿίϧʔνϯείʔϓͷίϯςΩετϝΠϯείʔϓίϧʔνϯίϧʔνϯίϧʔνϯ1ͷείʔϓείʔϓίϧʔνϯͷείʔϓείʔϓίϧʔνϯίϧʔνϯͷείʔϓείʔϓ
CoroutineContextͷྫ: Job ͋Δίϧʔνϯͷ࣮ߦΛද͢Πϯελϯε• ίϧʔνϯΛ࣮ߦ͢ΔͱJobΛ͔͑͢ɻ
CoroutineContextͷྫ: CorouttineDispatcher ίϧʔνϯΛͲͷεϨουͰಈ͔͔͢ΛܾΊΔਓ• Dispatches.Main• Dispatchers.Default• Dispatchers.IO• Dispatchers.Unconfined• ͦͷଞ: newSingleThreadContext("threadName")ͳͲ
CoroutinenContextͷྫ:ͦͷଞ• CoroutineName("name")• NonCancellable• CoroutineExceptionHandler {}
CoroutineContextͷ͍ํ• ίϧʔνϯϏϧμʔͷҾʹࢦఆͯ͠͏• + Ͱ࿈݁ʢॏෳͨ͠ઃఆӈล༏ઌʣͯ͠Έ߹Θͤͯ࡞Δ
CoroutineContextͷ͍ํ• ಉظతʹৼΔͬͯ͘ΕΔ withContext ͕ศར
Kotlin CoroutineͷΩϞᶅ Async as Sync
TwitterΫϥΠΞϯτతͳΞϓϦ࣮ΛίϧʔνϯͰߟ͑ΔɻϩάΠϯ0,λΠϜϥΠϯऔಘ<l͓Α͏z lࠓษڧձͰ͢z>
ίϧʔνϯඇಉظ• ྫ: ϩάΠϯͯ͠λΠϜϥΠϯऔಘ͢ΔAPI࣮
ίϧʔνϯඇಉظʁ• ඇಉظॲཧΛಉظతͳײ֮Ͱखଓ͖తʹॻ͚Δ
ίϧʔνϯඇಉظॲཧΛಉظతʢखଓ͖తʣʹॻ͚Δ• ಉظతʹॻ͚ΔͷͰɺײతͰɺόάΛຒΊࠐΈʹ͍͘ɻ(σουϩοΫɾ࣮ߦλΠϛϯά)• ͳΜͱ͔ListenerίʔϧόοΫࠈ͔Βͷղ์ɻ
async / await ͋Δ• async ίϧʔνϯͰɺඇಉظίϧʔνϯʹͭͭ͠ɺ݁ՌΛͭ͜ͱͰ͖Δ• async = ݁ՌΛड͚औΕΔػೳΛͭ launchɻ
Kotlin ίϧʔνϯͷجຊ͜Ε͚ͩ
Kotlin Coroutineͷศརͳػೳͷհ
flow ίϧʔνϯ• flow = γʔέϯεͰॱ࣍݁ՌΛྲྀ͢ async.• Rx ObservableΛࢀߟʹ࡞ΒΕ͍ͯΔɻ• map(transform{}), flatMap,ϑΟϧλ, ྫ֎෮ؼॲཧ(catch{}), εϨουΓସ͑,combineLatest, zip ͳͲ͋Δɻ
Channels, produce, actor• Channel ίϧʔνϯؒͷํͷσʔλΓऔΓʹ͔ͭ͑ΔΦϒδΣΫτɻ• produce { } ... ࢠ͕ૹ৴͕ͯ͠ड৴͢ΔҰํνϟϯωϧΛ࡞Δίϧʔνϯɻ• actor { } ... ͕ૹ৴ͯ͠ࢠ͕ड৴͢ΔҰํνϟωϧΛ࡞Δίϧʔνϯɻ
AndroidXͰ͑Δศརͳػೳ• ViewModelScope• LifecycleScope• liveData { LiveDataScope -> Unit ... }:LiveData