Save 37% off PRO during our Black Friday Sale! »

Coroutine Kyuin

2d855b951ff3160c55915821261432f9?s=47 uzzu
December 20, 2018

Coroutine Kyuin

社内勉強会「冬休み前にKotlinのCoroutinesを吸引したい人が集う会」資料

2d855b951ff3160c55915821261432f9?s=128

uzzu

December 20, 2018
Tweet

Transcript

  1. ౙٳΈલʹ ,PUMJOͷ$PSPVUJOFTΛ ٵҾ͍ͨ͠ਓ͕ू͏ձ !V[[V

  2. झࢫ w೥຤,PUMJOͰ੒Ռग़ͧ͢ w·ͩ$PSPVUJOFTΑ͘෼͔ͬͯͳ͍ͧ w$PSPVUJOFTରԠਓࡐʹͳΔͧ

  3. ຊ୊ w ,PUMJOϕʔεͰ࿩͠·͢  w$PSPVUJOFTͱ͸ wଞݴޠʹ͓͚ΔBTZODBXBJUͱͷҧ͍ w࢖͍ํͬ͘͟Γ wͱΓ͜ΕϦϯΫू

  4. $PSPVUJOFT w,PUMJO͔Βਖ਼ࣜϦϦʔε͞Εͨඇಉظϓϩάϥ ϛϯάͷҝͷػೳ ΋ͪΖΜNVMUJQMBUGPSNରԠ  wଞݴޠͰ͍͏ॴͷBTZODBXBJU౳ؚ͕·Ε͍ͯΔ wଞݴޠͰ͍͏ॴͷDPSPVUJOF HFOFSBUPS ͸
 ,PUMJOͰ͸4FRVFODF5

  5. 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(); }
  6. 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(); }
  7. 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(); }
  8. 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}`) })();
  9. 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}`) })();
  10. 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}`) })();
  11. BTZODBXBJU wBTZODGVODUJPOΛ࣮૷ͯ͠
 ݺͼग़͠ଆͰBXBJU͢Δ

  12. $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") }
  13. $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") }
  14. $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") }
  15. $PSPVUJOFT wTVTQFOEGVODUJPOΛ࣮૷ͯ͠
 ݺͼग़͠ଆ͸ͨͩݺͿ BXBJULFZXPSEͳ͠ 
 BTZODBXBJUͳݴޠͰ͸ඇಉظͰ͋Δࣄ͕લఏ
 ,PUMJOͰ͸ඇಉظؔ਺Ͱ͸ͳ͘தஅؔ਺ͳͷͰ
 ɹಉظzతzʹهड़Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ
 ɹଞݴޠͷΑ͏ʹಉظඇಉظΛҙࣝ͢Δඞཁ͕ͳ͍

  16. ࢖͍ํ w%FQFOEFODJFTͷ௥Ճ w$PSPVUJOF4DPQFΛ࣮૷͢Δ w$PSPVUJOF4DPQFMBVODIͯ͠
 Α͠ͳʹTVTQFOEGVODUJPOΛݺͼग़͢

  17. %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"

  18. $PSPVUJOF4DPQFΛ࣮૷͢Δ wTVTQFOEGVODUJPO͸$PSPVUJOFͷத͋Δ͍͸ TVTQFOEGVODUJPO͔ΒͷΈར༻Ͱ͖Δ w$PSPVUJOF͸$PSPVUJOF4DPQFͷதͰͷΈ
 ىಈͰ͖Δ w$PSPVUJOF4DPQFͷ࣮૷͕ඞཁ

  19. $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Λ࡞ͬͯ ࣮ߦ׬ྃ·Ͱ଴ͬͯΔ
  20. $PSPVUJOF4DPQFΛ࣮૷͢Δ w࣮૷ͷલʹগ͚ͩ͠ొ৔ਓ෺ͷ੔ཧ
 ਂೖΓ͢ΔͱऴΘΒͳ͍ͷͰগ͚ͩ͠

  21. ࣮૷͢Δ্Ͱ࠷௿ݶͷొ৔ਓ෺ w$PSPVUJOF$POUFYUϓϩύςΟͱͯ࣋ͭ͠ඞཁ͕͋Δ w+PCMBVODI͢Δ$PSPVUJOFͷϥΠϑαΠΫϧΛ؅ཧ w$PSPVUJOF%JTQBUDIFS࣮ߦίϯςΩετ 5ISFBEFUD  wଞɺ$PSPVUJOF&YDFQUJPO)BOEMFS౳͍Δ
 ͕Ұ୴์ஔ

  22. $PSPVUJOF4DPQFΛ࣮૷͢Δ class SimpleCoroutineScope(ui: CoroutineDispatcher) : CoroutineScope { // ਌JobΛ࡞Δ(࡞Ε) private

    val job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠
 // ਌Job͸jobϓϩύςΟͷ΍ͭ
 // ࣮ߦίϯςΩετ͸ίϯετϥΫλҾ਺uiΛ༻͍Δ override val coroutineContext: CoroutineContext = job + ui }
  23. $PSPVUJOF4DPQFΛ࣮૷͢Δ class SimpleCoroutineScope : CoroutineScope { // ਌JobΛ࡞Δ(࡞Ε) private val

    job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠
 // ਌Job͸jobϓϩύςΟͷ΍ͭ
 // ࣮ߦίϯςΩετ͸mainϧʔϓΛ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.Main }
  24. $PSPVUJOF4DPQFΛ࣮૷͢Δ class SimpleCoroutineScope : CoroutineScope { // ਌JobΛ࡞Δ(࡞Ε) private val

    job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠
 // ਌Job͸jobϓϩύςΟͷ΍ͭ
 // ࣮ߦίϯςΩετ͸IO Pool(※Threadͱ͸ݶΒͳ͍)Λ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.IO }
  25. $PSPVUJOF4DPQFMBVODI͢Δ w جຊతͳॴͱͯ͠ MBVODI͢Δͱ$PSPVUJOF͕ى ಈ͢Δ
 $PSPVUJOF͸࣮ࡍ͍ΖΜͳॴͰىಈ͍ͯ͠Δ͚Ͳলུ wMBVODIͷલʹొ৔ਓ෺Λʜ

  26. ొ৔ਓ෺ w$PSPVUJOF4DPQF͖ͬ͞࡞ͬͨ΍ͭ w$PSPVUJOF$POUFYU͖ͬ͞ϓϩύςΟʹ࣋ͨͤͨ΍ͭ w$PSPVUJOFMBVODI౳ʹΑͬͯ࡞ΒΕΔ࣮ࡍʹಈ͍ͯΔ΍ͭ w+PC  ུ %JTQBUDIFS FUDʜ͖ͬ͞આ໌ͨ͠΍ͭ wଞɺ$PSPVUJOF4UBSU౳͋Δ͕Ұ୴লུ

  27. $PSPVUJOF4DPQFMBVODI͢Δ class SimpleCoroutineScope : CoroutineScope { // ਌JobΛ࡞Δ(࡞Ε) private val

    job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠
 // ਌Job͸jobϓϩύςΟͷ΍ͭ
 // ࣮ߦίϯςΩετ͸mainϧʔϓΛ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.Main }
  28. $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() } } }
  29. $PSPVUJOF4DPQFMBVODI͢Δ class SimpleCoroutineScope : CoroutineScope { // ਌JobΛ࡞Δ(࡞Ε) private val

    job: Job = Job() // σϑΥϧτͷڍಈͱͯ͠
 // ਌Job͸jobϓϩύςΟͷ΍ͭ
 // ࣮ߦίϯςΩετ͸IO Pool(※Threadͱ͸ݶΒͳ͍)Λ༻͍Δ override val coroutineContext: CoroutineContext = job + Dispatchers.IO }
  30. $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() } } }
  31. $PSPVUJOF4DPQFMBVODI͢Δ wิ଍ɿ͜Ε͸DPNQJMFFSSPS SFUVSOͰ͖ͳ͍ fun execute(): Int { launch { return

    doSomething() } }
  32. 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") }
  33. 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
  34. 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}`) })();
  35. 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}`) })(); Ԟ஍Ͱ͜Ε૬౰ͷͳʹ͔Λ
 ࣮૷͢Δඞཁ͕͋Δ
  36. TVTQFOEGVODUJPOΛ࣮૷͢Δ w࣮૷ͷલʹొ৔ਓ෺Λʜ

  37. TVTQFOEGVODUJPOΛ࣮૷͢Δ wTVTQFOE$PSPVUJOFTVTQFOEGVODUJPOΛ࣮૷͢Δҝͷ ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ#VJMEFSGVODUJPO w$POUJOVBUJPOTVTQFOEGVODUJPOΛ࠶։͢Δҝͷ&NJUUFSɹ wଞɺTVTQFOE $PSPVUJOFɺ $POUJOVBUJPO
 γϦʔζ͕͍͔ͭ͋͘Δ͚ͲҰ୴লུ

  38. TVTQFOEGVODUJPOΛ࣮૷͢Δ suspend fun doSomething(value: Int): Int = suspendCoroutine { continuation

    -> continuation.resume(value * value) } suspend fun doSomething(value: Int): Int = suspendCoroutine { continuation -> continuation.resumeWithException(Throwable()) }
  39. طଘίʔυΛ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) } }) }
  40. طଘίʔυΛ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"
  41. ྫ֎र͍͍ͨ launch { try { val result = doSomething() }

    catch (e: Throwable) { // } } launch { runCatching { doSomething() } // Result<T>͕ฦ٫͞ΕΔ .onSuccess { value -> } .onFailure { throwable -> } } ,PUMJO͔Β௥ՃͷSVO$BUDIJOHਪ঑
  42. ࣮ߦίϯςΩετม͍͑ͨ 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 } } } }
  43. Ωϟϯηϧ͍ͨ͠ $ 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}"); }
  44. Ωϟϯηϧ͍ͨ͠ &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Ͱϓϩηεؒ௨৴ͭͭ͠௕ظλεΫ࣮ߦͯͯ͠ʜͳ࣌ͱ͔
  45. Ωϟϯηϧ͍ͨ͠ class SimpleCoroutineScope : CoroutineScope { private val job: Job

    = Job() override val coroutineContext: CoroutineContext = job + Dispatchers.Main fun onDestroy() { job.cancel() } }
  46. Ωϟϯηϧ͍ͨ͠ class SimpleCoroutineScope : CoroutineScope { private val job: Job

    = Job() override val coroutineContext: CoroutineContext = job + Dispatchers.Main fun onDestroy() { job.cancel() } } ࢠͷJob(Coroutine)͕શ෦cancel͞ΕΔ ݸผʹcancel͍ͨ͠έʔεʹ͍ͭͯ͸লུ
  47. ͱΓ͜ΕϦϯΫू w$PSPVUJOF(VJEF
 IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFTCMPC NBTUFSDPSPVUJOFTHVJEFNE
 ೔ຊޠ༁IUUQTHJUIVCDPNQMKQLPUMJOYDPSPVUJOFTCMPC KBQBOFTF@USBOTMBUJPODPSPVUJOFTHVJEFNE w,PUMJO$POGͰࢀՃͨ͠XPSLTIPQ
 IUUQTHJUIVCDPNFMJ[BSPW$PSPVUJOFT8PSLTIPQ
 ຊ౰ʹॳาతͳॴ͔Β"DUPS 1SPEVDFS·Ͱ෼͔Δ

  48. Ұ୴͜͜·Ͱ

  49. ଞτϐοΫฉ͖͍ͨࣄ͋Ε͹ޙ΄ͲͲ͏ͧ 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ؔ࿈