完全に理解した気になるKotlin Coroutines

coroutinesを使うとスレッドをブロックしたり、コールバックなしにコードを書いていくことができます。
ただ、自分がコードを見たときには魔法にしか見えなかったので、coroutinesの本質に迫っていきたいと考えました。


# launch coroutineビルダーによる実行
まず最も利用されるlaunchについて説明していきます。
以下のように書いた時にThreadはどうなっているでしょうか？

```java
launch {
  println("thread:"+Thread.currentThread())
}
```
以下のようにログが出力されます。
thread:Thread[ForkJoinPool.commonPool-worker-2,5,main]

このForkJoinPool.commonPool-workerはどこから来ているのでしょうか？
launchの引数のDefaultDispatcherを見てきましょう。**実はこの引数のCoroutineContextによって実行されるThreadが決まります。**

```kotlin
public fun launch(
    context: CoroutineContext = DefaultDispatcher, 
    start: CoroutineStart = CoroutineStart.DEFAULT,
    parent: Job? = null,
    onCompletion: CompletionHandler? = null,
    block: suspend CoroutineScope.() -> Unit
): Job {
```

DefaultDispatcherは以下のようになっています。つまり**DefaultDispatcherはCommonPool**です。

```kotlin
public actual val DefaultDispatcher: CoroutineDispatcher = CommonPool
```

CommonPoolはどうなっているでしょうか？
https://github.com/Kotlin/kotlinx.coroutines/blob/1ce6c0b223db39ce8a75ae08b9d9624a6554e34f/core/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/CommonPool.kt

**Thread Poolがなければ作り渡されたblockをThread Poolでexecuteしています。ここで実際に`println("thread:"+Thread.currentThread())`が実行されます。**

```kotlin
    override fun dispatch(context: CoroutineContext, block: Runnable) =
        try { (pool ?: getOrCreatePoolSync()).execute(timeSource.trackTask(block)) }
        catch (e: RejectedExecutionException) {
            timeSource.unTrackTask()
            DefaultExecutor.execute(block)
        }
```

実際に自分でDispatcherを作るとどうなるでしょうか？
**以下のようにそのままのThreadで実行するようなことができます。**

```kotlin
fun main(args: Array<String>) {
    launch(MyDispacher()) {
        println("thread:"+Thread.currentThread())
    }
}

class MyDispacher : CoroutineDispatcher() {
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        println("dispatch:before")
        block.run()
        println("dispatch:after")
    }
}

```

Thread Poolで実行していないので、Main Threadでそのまま実行されていることが分かります。

```
dispatch:before
thread:Thread[main,5,main]
dispatch:after
```

ここまではCoroutineってthreadと同じようなものだと思うかもしれません。
Coroutineは**中断**ができます

# 中断

suspendCoroutine()はdelay()やawait()などといった中断を行うメソッドの中で使われるメソッドです。
これを使うとCoroutineの中断をすることができます。
中断すると何が起こるかというと、そのThreadでの実行を一度やめて、もう一度走り直します。
`resume`を使うことで、中断されたCoroutinesを再開することができます。

```kotlin
fun main(args: Array<String>) {
    launch(MyDispatcher()) {
        println("1:" + Thread.currentThread())
        suspendCoroutine<String> { continuation ->
            thread {
                // 普通にthreadを作って実行する
                // 中断されたCoroutinesを再開する
                continuation.resume("test")
            }
        }
        println("2:" + Thread.currentThread())
    }

    Thread.sleep(1000)
}

class MyDispatcher : CoroutineDispatcher() {
    val executor = Executors.newSingleThreadExecutor()
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        executor.execute {
            println("dispatch:before")
            block.run()
            println("dispatch:after")
        }
    }
}
```

```
dispatch:before
1:Thread[pool-1-thread-1,5,main]
dispatch:after
# **ここで一度中断している**
dispatch:before
2:Thread[pool-1-thread-1,5,main]
dispatch:after
```

# 実践Coroutines

Androidでは`launch(UI)`を利用するとUI Threadで実行します。想像がつくかもしれませんが、`launch(UI)`を利用すると[AndroidのHandlerによって実行されます](https://github.com/Kotlin/kotlinx.coroutines/blob/1ce6c0b223db39ce8a75ae08b9d9624a6554e34f/ui/kotlinx-coroutines-android/src/main/kotlin/kotlinx/coroutines/experimental/android/HandlerContext.kt#L51)。

```kotlin
launch(UI) {
  val response = api.fetch()
  Snackbar.make(view, "code:${response.code}", Snackbar.LENGTH_LONG)
    .setAction("Action", null).show()
}
```

HandlerContextの中で、**AndroidのHandlerにただRunnableをpostしているだけ**で簡単ですね。

```kotlin
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        handler.post(block)
    }
```

今回のfetch()メソッドの中は以下のようになっています。

```kotlin
    interface ApiSearvice {
        @GET("/")
        fun fetchDefferd(@Query("zipcode") zipCode: String = "1000000"): Deferred<Response>
    }

    val service = retrofit.create(ApiSearvice::class.java)
    
    // わざわざsuspendメソッドでラップしている
    suspend fun fetch(): Response {
        return service.fetchDefferd().await()
    }
```


[retrofit2-kotlin-coroutines-adapter](https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter)を使っていますが、わざわざsuspendメソッドでラップしています。なぜなら使う側で中断関数await()を呼ぶ必要がなくなるからです。
こちらについては[KotlinのドキュメントのAsynchronous programming stylesを読む](https://qiita.com/takahirom/items/a0726c506dc1efacc5be)で説明していて、suspendを使ってawaitをなるべく使わないようにすることで、よりKotlinらしく書くことができると記載があります。(retrofit2-kotlin-coroutines-adapterはissueも上がっていてこれに対応してほしい。直せるかなってcloneして見てみたけどRetrofitの仕組み的に難しそうだった。。)
これまでの傾向で、どのThreadで通信処理が動いているのか気になるかもしれません。通信処理はOkHttpのスレッドで実行されて、await()のタイミングでCorouitnesが中断して、取得でき次第再開します。

# 終わりに
どうでしょうか、完全に理解できましたかね？多分無理だと思うので、
ここまで読んだ上で@k-kagurazaka@githubさんの[入門Kotlin coroutines](https://qiita.com/k-kagurazaka@github/items/8595ca60a5c8d31bbe37)に入るとすんなり理解できてくるかもしれません。