Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Coroutine Kyuin

uzzu
December 20, 2018

Coroutine Kyuin

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

uzzu

December 20, 2018
Tweet

More Decks by uzzu

Other Decks in Technology

Transcript

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

    View Slide

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

    View Slide

  3. ຊ୊
    w ,PUMJOϕʔεͰ࿩͠·͢

    w$PSPVUJOFTͱ͸
    wଞݴޠʹ͓͚ΔBTZODBXBJUͱͷҧ͍
    w࢖͍ํͬ͘͟Γ
    wͱΓ͜ΕϦϯΫू

    View Slide

  4. $PSPVUJOFT
    w,PUMJO͔Βਖ਼ࣜϦϦʔε͞Εͨඇಉظϓϩάϥ
    ϛϯάͷҝͷػೳ ΋ͪΖΜNVMUJQMBUGPSNରԠ

    wଞݴޠͰ͍͏ॴͷBTZODBXBJU౳ؚ͕·Ε͍ͯΔ
    wଞݴޠͰ͍͏ॴͷDPSPVUJOF HFOFSBUPS
    ͸

    ,PUMJOͰ͸4FRVFODF5

    View Slide

  5. BTZODBXBJU $

    class Program
    {
    static async ValueTask 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();
    }

    View Slide

  6. BTZODBXBJU $

    class Program
    {
    static async ValueTask 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();
    }

    View Slide

  7. BTZODBXBJU $

    class Program
    {
    static async ValueTask 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();
    }

    View Slide

  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}`)
    })();

    View Slide

  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}`)
    })();

    View Slide

  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}`)
    })();

    View Slide

  11. BTZODBXBJU
    wBTZODGVODUJPOΛ࣮૷ͯ͠

    ݺͼग़͠ଆͰBXBJU͢Δ

    View Slide

  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")
    }

    View Slide

  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")
    }

    View Slide

  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")
    }

    View Slide

  15. $PSPVUJOFT
    wTVTQFOEGVODUJPOΛ࣮૷ͯ͠

    ݺͼग़͠ଆ͸ͨͩݺͿ BXBJULFZXPSEͳ͠

    BTZODBXBJUͳݴޠͰ͸ඇಉظͰ͋Δࣄ͕લఏ

    ,PUMJOͰ͸ඇಉظؔ਺Ͱ͸ͳ͘தஅؔ਺ͳͷͰ

    ɹಉظzతzʹهड़Ͱ͖ΔΑ͏ʹͳ͍ͬͯΔ

    ɹଞݴޠͷΑ͏ʹಉظඇಉظΛҙࣝ͢Δඞཁ͕ͳ͍

    View Slide

  16. ࢖͍ํ
    w%FQFOEFODJFTͷ௥Ճ
    w$PSPVUJOF4DPQFΛ࣮૷͢Δ
    w$PSPVUJOF4DPQFMBVODIͯ͠

    Α͠ͳʹTVTQFOEGVODUJPOΛݺͼग़͢

    View Slide

  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"

    View Slide

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

    ىಈͰ͖Δ
    w$PSPVUJOF4DPQFͷ࣮૷͕ඞཁ

    View Slide

  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Λ࡞ͬͯ
    ࣮ߦ׬ྃ·Ͱ଴ͬͯΔ

    View Slide

  20. $PSPVUJOF4DPQFΛ࣮૷͢Δ
    w࣮૷ͷલʹগ͚ͩ͠ొ৔ਓ෺ͷ੔ཧ

    ਂೖΓ͢ΔͱऴΘΒͳ͍ͷͰগ͚ͩ͠

    View Slide

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

    wଞɺ$PSPVUJOF&YDFQUJPO)BOEMFS౳͍Δ

    ͕Ұ୴์ஔ

    View Slide

  22. $PSPVUJOF4DPQFΛ࣮૷͢Δ
    class SimpleCoroutineScope(ui: CoroutineDispatcher) : CoroutineScope {
    // ਌JobΛ࡞Δ(࡞Ε)
    private val job: Job = Job()
    // σϑΥϧτͷڍಈͱͯ͠

    // ਌Job͸jobϓϩύςΟͷ΍ͭ

    // ࣮ߦίϯςΩετ͸ίϯετϥΫλҾ਺uiΛ༻͍Δ
    override val coroutineContext: CoroutineContext = job + ui
    }

    View Slide

  23. $PSPVUJOF4DPQFΛ࣮૷͢Δ
    class SimpleCoroutineScope : CoroutineScope {
    // ਌JobΛ࡞Δ(࡞Ε)
    private val job: Job = Job()
    // σϑΥϧτͷڍಈͱͯ͠

    // ਌Job͸jobϓϩύςΟͷ΍ͭ

    // ࣮ߦίϯςΩετ͸mainϧʔϓΛ༻͍Δ
    override val coroutineContext: CoroutineContext =
    job + Dispatchers.Main
    }

    View Slide

  24. $PSPVUJOF4DPQFΛ࣮૷͢Δ
    class SimpleCoroutineScope : CoroutineScope {
    // ਌JobΛ࡞Δ(࡞Ε)
    private val job: Job = Job()
    // σϑΥϧτͷڍಈͱͯ͠

    // ਌Job͸jobϓϩύςΟͷ΍ͭ

    // ࣮ߦίϯςΩετ͸IO Pool(※Threadͱ͸ݶΒͳ͍)Λ༻͍Δ
    override val coroutineContext: CoroutineContext =
    job + Dispatchers.IO
    }

    View Slide

  25. $PSPVUJOF4DPQFMBVODI͢Δ
    w جຊతͳॴͱͯ͠
    MBVODI͢Δͱ$PSPVUJOF͕ى
    ಈ͢Δ

    $PSPVUJOF͸࣮ࡍ͍ΖΜͳॴͰىಈ͍ͯ͠Δ͚Ͳলུ
    wMBVODIͷલʹొ৔ਓ෺Λʜ

    View Slide

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

    View Slide

  27. $PSPVUJOF4DPQFMBVODI͢Δ
    class SimpleCoroutineScope : CoroutineScope {
    // ਌JobΛ࡞Δ(࡞Ε)
    private val job: Job = Job()
    // σϑΥϧτͷڍಈͱͯ͠

    // ਌Job͸jobϓϩύςΟͷ΍ͭ

    // ࣮ߦίϯςΩετ͸mainϧʔϓΛ༻͍Δ
    override val coroutineContext: CoroutineContext =
    job + Dispatchers.Main
    }

    View Slide

  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()
    }
    }
    }

    View Slide

  29. $PSPVUJOF4DPQFMBVODI͢Δ
    class SimpleCoroutineScope : CoroutineScope {
    // ਌JobΛ࡞Δ(࡞Ε)
    private val job: Job = Job()
    // σϑΥϧτͷڍಈͱͯ͠

    // ਌Job͸jobϓϩύςΟͷ΍ͭ

    // ࣮ߦίϯςΩετ͸IO Pool(※Threadͱ͸ݶΒͳ͍)Λ༻͍Δ
    override val coroutineContext: CoroutineContext =
    job + Dispatchers.IO
    }

    View Slide

  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()
    }
    }
    }

    View Slide

  31. $PSPVUJOF4DPQFMBVODI͢Δ
    wิ଍ɿ͜Ε͸DPNQJMFFSSPS SFUVSOͰ͖ͳ͍

    fun execute(): Int {
    launch {
    return doSomething()
    }
    }

    View Slide

  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")
    }

    View Slide

  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

    View Slide

  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}`)
    })();

    View Slide

  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}`)
    })();
    Ԟ஍Ͱ͜Ε૬౰ͷͳʹ͔Λ

    ࣮૷͢Δඞཁ͕͋Δ

    View Slide

  36. TVTQFOEGVODUJPOΛ࣮૷͢Δ
    w࣮૷ͷલʹొ৔ਓ෺Λʜ

    View Slide

  37. TVTQFOEGVODUJPOΛ࣮૷͢Δ
    wTVTQFOE$PSPVUJOFTVTQFOEGVODUJPOΛ࣮૷͢Δҝͷ
    ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ#VJMEFSGVODUJPO
    w$POUJOVBUJPOTVTQFOEGVODUJPOΛ࠶։͢Δҝͷ&NJUUFSɹ
    wଞɺTVTQFOE$PSPVUJOFɺ$POUJOVBUJPO

    γϦʔζ͕͍͔ͭ͋͘Δ͚ͲҰ୴লུ

    View Slide

  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())
    }

    View Slide

  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)
    }
    })
    }

    View Slide

  40. طଘίʔυΛTVTQFOEGVO
    w3FBDUJWFd͔ΒҠߦ͍ͨ͠৔߹͸ม׵༻ϥΠϒϥϦΛ࢖͏

    ҎԼ͸3Y+BWBͷྫ

    fun doSomethingSingle(value: Int): Single =
    Single.just(value * value)
    suspend fun doSomething(value: Int): Int =
    doSomethingSingle(value).await()
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:1.0.1"

    View Slide

  41. ྫ֎र͍͍ͨ
    launch {
    try {
    val result = doSomething()
    } catch (e: Throwable) {
    //
    }
    }
    launch {
    runCatching { doSomething() } // Result͕ฦ٫͞ΕΔ
    .onSuccess { value -> }
    .onFailure { throwable -> }
    }
    ,PUMJO͔Β௥ՃͷSVO$BUDIJOHਪ঑

    View Slide

  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
    }
    }
    }
    }

    View Slide

  43. Ωϟϯηϧ͍ͨ͠ $

    static async ValueTask 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}");
    }

    View Slide

  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Ͱϓϩηεؒ௨৴ͭͭ͠௕ظλεΫ࣮ߦͯͯ͠ʜͳ࣌ͱ͔

    View Slide

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

    View Slide

  46. Ωϟϯηϧ͍ͨ͠
    class SimpleCoroutineScope : CoroutineScope {
    private val job: Job = Job()
    override val coroutineContext: CoroutineContext =
    job + Dispatchers.Main
    fun onDestroy() {
    job.cancel()
    }
    }
    ࢠͷJob(Coroutine)͕શ෦cancel͞ΕΔ
    ݸผʹcancel͍ͨ͠έʔεʹ͍ͭͯ͸লུ

    View Slide

  47. ͱΓ͜ΕϦϯΫू
    w$PSPVUJOF(VJEF

    IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFTCMPC
    NBTUFSDPSPVUJOFTHVJEFNE

    ೔ຊޠ༁IUUQTHJUIVCDPNQMKQLPUMJOYDPSPVUJOFTCMPC
    [email protected]
    w,PUMJO$POGͰࢀՃͨ͠XPSLTIPQ

    IUUQTHJUIVCDPNFMJ[BSPW$PSPVUJOFT8PSLTIPQ

    ຊ౰ʹॳาతͳॴ͔Β"DUPS 1SPEVDFS·Ͱ෼͔Δ

    View Slide

  48. Ұ୴͜͜·Ͱ

    View Slide

  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

    KPCEJTQBUDIFS ʜ
    ͬͯԿ

    ͲΜͳίʔυʹͳΔͷόΠτίʔυݟͳ͕Β

    $PSPVUJOFͷத਎Ͳ͏ͳͬͯΜͷιʔείʔυಡΈͳ͕Β

    NVMUJQMBUGPSNؔ࿈

    View Slide