Kotlin 1.3のCoroutineのサスペンド関数の合成③（ゆっくりとasyncを実行）

# 検証環境
この記事の内容は、以下の環境で検証しました。

* Intellij IDEA ULTIMATE 2018.2
* Kotlin 1.3.0
* Gradle Projectで作成
* GradleファイルはKotlinで記述（KotlinでDSL）

# 準備
詳細は下記の準備を参照してください。
https://qiita.com/naoi/items/8abf2cddfc2cb3802daa

# Lazily started async
[前回](https://qiita.com/naoi/items/dc55b93c69c52d079486)に引き続き、[公式サイト](http://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html#lazily-started-async)を読み解いていきます。

タイトルを見てみるとゆっくり実行って・・・。日本語にするとよくわからないですが、英名で考えると意外とすんなり理解できます。lazilyという単語からlazyで連想した場合、Kotlinだとあとで実行するとイメージするんではないでしょうか？
ということは、今回は、asyncを任意のタイミングで実行する方法と考えられます。

早速、公式サイトを読み進めてみます。

> There is a laziness option to async using an optional start parameter with a value of CoroutineStart.LAZY. It starts coroutine only when its result is needed by some await or if a start function is invoked. Run the following example:

訳すと。

> async関数のパラメータとして、startにCoroutineStart.LAZYを指定すると実行を遅らせることができます。
> コルーチンの処理を開始するには、start関数を呼び出すか、他のコルーチンの処理結果を待つ場合のみです。
> サンプルコードをみてみましょう。

ということは、即時で実行したい場合は、async関数に引数が必要だといことがわかりました。
また、start関数で処理を実行は理解できます。しかし、他のコルーチンの結果を待って処理を実行するイメージがつきません。

サンプルコードを確認したら理解できるかもしれません。
確認してみます。

```kotlin
import kotlinx.coroutines.*
import kotlin.system.*

fun main() = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
        val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
        // some computation
        one.start() // start the first one
        two.start() // start the second one
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")    
}

suspend fun doSomethingUsefulOne(): Int {
    delay(1000L) // pretend we are doing something useful here
    return 13
}

suspend fun doSomethingUsefulTwo(): Int {
    delay(1000L) // pretend we are doing something useful here, too
    return 29
}
```
async関数の引数にパラメータを渡して、start関数呼び出しで処理を開始しています。
実行結果も確認してみましょう。

```text
The answer is 42
Completed in 1026 ms
```

前回と変化は無いみたいですが、並列で処理は行われているみたいです。
公式サイトには、続きがあるので、読み進めてみます。

> So, here the two coroutines are defined but not executed as in the previous example, but the control is given to the programmer on when exactly to start the execution by calling start. We first start one, then start two, and then await for the individual coroutines to finish.

>Note, that if we have called await in println and omitted start on individual coroutines, then we would have got the sequential behaviour as await starts the coroutine execution and waits for the execution to finish, which is not the intended use-case for laziness. The use-case for async(start = CoroutineStart.LAZY) is a replacement for the standard lazy function in cases when computation of the value involves suspending functions.

訳すと

> サンプルコードでは、2つのコルーチンが実行されます。しかし、これまでとは違い実行するタイミングはプログラマーによります。今回はれいでは、1つ目のコルーチン実行後、2つ目のコルーチンが実行されています。

> start関数を呼び出さず、await関数を呼び出すと、コルーチンを実行します。更に、await関数によって実行されたコルーチンの処理をまちます。
>  async（start = CoroutineStart.LAZY）を指定した場合、処理内にdelayが存在すると、通常の一時停止になります。

start関数を記述せずに、awaitを呼び出すと実行されるみたいです。
実際に試してみましょう。

```kotlin
fun main() = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
        val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
        // some computation

        
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

suspend fun doSomethingUsefulOne(): Int {
    delay(1000L) // pretend we are doing something useful here
    return 13
}

suspend fun doSomethingUsefulTwo(): Int {
    delay(1000L) // pretend we are doing something useful here, too
    return 29
}
```

上記のように書き直してみました。
実行してみると。

```text
The answer is 42
Completed in 2026 ms
```

実行はされているみたいですが、並列で処理はおこなわれていないですね。
やはり、関数を呼び出して完了してから次の関数を呼び出していることがわかります。


ちにみに、await関数を記述しないとどうなるかもきになります。
以下のように書き換えてみました。

```kotlin
import kotlinx.coroutines.*
import kotlin.system.*

fun main() = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
        val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
        // some computation


        println("The answer is ${one}")
    }

    println("Completed in $time ms")
}

suspend fun doSomethingUsefulOne(): Int {
    delay(1000L) // pretend we are doing something useful here
    return 13
}

suspend fun doSomethingUsefulTwo(): Int {
    delay(1000L) // pretend we are doing something useful here, too
    return 29
}
```

実行してみると。

```text
The answer is LazyDeferredCoroutine{New}@5a8e6209
Completed in 8 ms
```

内容を確認すると、どうやらコルーチンの処理は実行されていないみたいです。
なるほどと言ったところです。

今回、async関数のstartに渡した  **CoroutineStart.LAZY** ですが、4種類あるようです。
よくわからないものもありますが、確認してみます。
[API表](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-start/index.html)も意訳込みですが、訳してみます。


|値|説明|
|:----|:----|
|DEFAULT|Contextに従って実行します。|
|LAZY|この記事で説明した通りです。|
|ATOMIC|原始的です。キャンセル不可能で、処理の文脈に従って実行します。DEFAULTによく似ていますが、実行前にキャンセルはできません。|
|UNDISPATCHED|コルーチンがあたかもDispatchers.Unconfinedによって実行されたように、サスペンドするポイントまで実行され、再開するときにはCoroutineDispatcherよって再開されます。|


# まとめ
このブロックで理解できたことは以下のことだと思います。

* async関数の引数にCoroutineStart.LAZYを指定すると任意のタイミングで実行できるコルーチンが生成できる
* Deferredのstart関数を呼び出すと処理が始まる
* start関数を呼び出さずにawaitを呼び出すとコルーチンを実行し、処理が終わるまで待つ