Kotlin の Coroutine について

https://raw.githubusercontent.com/JetBrains/kotlin-web-site/master/pages/docs/reference/coroutines.md の雑な訳。Apache 2.0.


# Coroutines - コルーチン

> コルーチンは Kotlin 1.1+ において *試験的な* 機能。

いくつかの API は長期間における処理をする（NetworkID, file IO, CPU- or GPU-intensive work 等)その場合呼び出し元をブロックしてしまうのだけど、コルーチンはブロックをさけ、ブロックを *一次停止*する手段を提供する。

コルーチンによって、複雑性がライブラリの中に隠蔽されて非同期プログラミングがよりシンプルになる。プログラムのロジックはコルーチンの中で *sequentially* として表現されて、基盤を提供するライブラリが非同期性を処理してくれる。ライブラリはユーザーコードをコールバックにラップ、イベントの購読、他のスレッドでの実行などを管理する。それでもコードは順次実行のようなシンプルさを保つ。

他の言語で利用されている非同期メカニズムもKotlinコルーチンを利用して実装する事ができる。以下を含む

* [`async`/`await`](https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#composing-suspending-functions) from C# and ECMAScript
* [channels](https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#channels) and [`select`](https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#select-expression) from Go.
* [generators/`yield`](#generators-api-in-kotlincoroutines) from C# and Python.

 See the description [below](#standard-apis) for libraries providing such constructs.

## ブロッキング v.s. サスペンディング

基本的に、コルーチンの処理はスレッドブロッキング無しにサスペンド可能。スレッドブロッキングは得てしてコストが高い（特にロードが高い場合は）。何故なら比較的少ない数のスレッドだけを保持できるので、一つのスレッドがブロックすると他の作業を送らせることになってしまうから。

コルーチンのサスペンディングはほとんどコストが無い。コンテキストスイッチや他の OS の関与が不要。さらになにより、これはユーザーライブラリによってコントロールされるので非常に高い拡張の余地がある。ライブラリの作者によってサスペンションのときに最適化/ログ/インターセプトなどを必要に応じて実装できる。

コルーチンのもうひとつのちがいとして、コルーチンは任意の場所で停止されることは無く、 *suspension points* と呼ばれる特別にマークされた関数のみで停止される。


## サスペンディング関数

サスペンドは `suspend`とマークされた特別な関数でのみ起こる:

``` kotlin 
suspend fun doSomething(foo: Foo): Bar { ... }
```

このような関数は *suspending functions* と呼ばれる。何故ならこれを呼ぶタイミングでcoroutine がサスペンドするかもしれないから (ライブラリ側で、実行準備が整っていないと判断すればサスペンドしないこともある). サスペンディングファンクションはパラメーターや返値を持つことは普通の関数と同じだが、コルーチンや他のサスペンディングファンクションからしか呼べないという違いがある。インライン展開された関数でも同じ。

実際に、コルーチンを開始するためにはサスペンディング関数が必要で、よくサスペンディングラムダで表現される。 例えば例はこのような物： `async()` function (from the [`kotlinx.coroutines`](#generators-api-in-kotlincoroutines) library):

``` kotlin
fun <T> async(block: suspend () -> T)
```


この `async()` は通常関数で (`suspending function`ではない), だが、 `block` パラメーターを取るラムダはサスペンディングファンクションで、 *suspending lambda* と呼ばれる。この中からはサスペンディングファンクションを呼ぶことが可能で

``` kotlin
async {
    doSomething(foo)
    ...
}
```

> **ノート:** 現在、サスペンディングファンクションの型は `supertype` としては使えず、非同期サスペンディング関数もサポートされない。

コルーチンのアナロジーとして `await()` もまたサスペンディングファンクションであり (そのため、 `async {}` blockから呼び出せる)他のコルーチンの実行まで、コルーチンをサスペンドさせる

``` kotlin
async {
    ...
    val result = computation.await()
    ...
}
```

`async/await` 関数がどのように動くかの詳細は `kotlinx.coroutines` の中で見つけることができる [こちら](https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#composing-suspending-functions).

`await()` や `doSomething()` は通常のファンクション、インライン化されていないファンクションリテラルや通常 main の中では呼び出せない。

``` kotlin
fun main(args: Array<String>) {
    doSomething() // ERROR: Suspending function called from a non-coroutine context 
    
    async { 
        ...
        computations.forEach { // `forEach` is an inline function, the lambda is inlined
            it.await() // OK
        }
            
        thread { // `thread` is not an inline function, so the lambda is not inlined
            doSomething() // ERROR
        }
    }
}
```

更に、サスペンディング関数は仮想関数たりえ、オーバーライドされる場合も `suspend` modifier の指定が必須である。

``` kotlin
interface Base {
    suspend fun foo()
}

class Derived: Base {
    override suspend fun foo() { ... }
}
```

### `@RestrictsSuspension` アノテーション
 
Extension functions (and lambdas) も `suspend` とマークが可能で通常の suspend 関数と同様に動く. これによって [DSLs](type-safe-builders.html) や他の API もこの拡張を使うことができる。。いくつかのケースでは、ライブラリの作者は、Suspending function の中でユーザーが任意にサスペンドすることを禁止したいかもしれない。

そのため [`@RestrictsSuspension`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-restricts-suspension/index.html) アノテーションを使うことができる。レシーバークラスやインターフェース `R` がこれでアノテーションされると、全てのサスペンド拡張は R メンバーへ委譲または。エクステンション同士はお互い無制限に委譲することはできないので、これはライブラリ作者が `R` のメンバーを呼んでいるタイミングのサスペンドをライブラリ作者が完全にコントロールできることを意味する。（ここらへんなんとなく解るけど訳はゴミ

想定的に希なケースとして、全てのサスペンドはライブラリで把握したいと思うかも知れない。例えば、[`buildSequence()`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/build-sequence.html) 関数を（[see below](#generators-api-in-kotlincoroutines)) を実装しているときなどに、以下の事を確実にする必要がああります。

> コルーチン内のどのようなsuspending call も yeld() または yeldAll() で終了し、他の関数では終了しない。

これが [`SequenceBuilder`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-sequence-builder/index.html) が `@RestrictsSuspension` でアノテーションされている理由です:

``` kotlin
@RestrictsSuspension
public abstract class SequenceBuilder<in T> { ... }
```
 
See the sources [on Github](https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/coroutines/experimental/SequenceBuilder.kt).   

## コルーチンの内部挙動

このばで詳細な開設はしないが、何が重要かだけ。

コルーチンはコンパーラー技術で実装されていて（JVM または OS 技術は利用していない）、サスペンションはコード変換で動く。基本的に、全てのサスペンディング関数（最適化が実行されるかも知れないがここでは触れない）は、サスペンディングコールに対応したステートマシーンに変換される。サスペンションがおこると、次の状態がコンパイラが生成したフィールドに保存される（実行場所と、ローカル変数など）。コルーチンがレジュームされると、ローカル変数がリストアされて、中断された場所から実行が再開される。

サスペンドされたコルーチンは保存、引き渡し可能。そのようなオブジェクトの型は `Continuation`。ここで触れたような全体的なコード変換の詳細は次で詳細に書かれている corresponds to the classical [Continuation-passing style](https://en.wikipedia.org/wiki/Continuation-passing_style). 従って、サスペンド関数は `continuation` という追加引数もを持っている。

コルーチンがさらにどのように動くかの詳細は、 [this design document](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md) で見つかる。実装された言語機能は Kotlin のコルーチンほど一般的ではないかもしれないが、他の言語での `async` / `await` （C＃やECMAScript 2016など）の同様の記述も参考になる。

## コルーチンの状況

コルーチンのデザインは [実験的](compatibility.html#experimental-features) であり, 将来のリリースで変更される可能性がある. コンパイル時にフラグを設定しないと *The feature "coroutines" is experimental* が表示される。非表示にするためには明示的な[opt-in flag](/docs/diagnostics/experimental-coroutines.html) が必要.

エクスペリメンタルなステータスのため、コルーチン関係の API で標準ライブラリに同梱されている物は `kotlin.coroutines.experimental` package にある. デザインが Fix されたら `kotlin.coroutines`にリフトアップされる予定。experimental package 自体は後方互換性のため（他のアーティファクトとして？）維持されるんじゃないかな. 

**重要**: ライブラリ作者にも同じコンベンションに従うことをオススメ "experimental" を追加して、例えば `com.example.experimental` のような suffix をコルーチンを使うパッケージに使って欲しい。最終的に APIが Fix したら
 * 全ての API を `com.example` にコピーし(experimental 接頭辞を削除する),
 * experimental package を後方互換性のために残しておく
 
これによって、ユーザーのマイグレーション問題を最小化できる

## Standard APIs
 
コルーチンの中核は以下の3つ
Coroutines come in three main ingredients: 
 - 言語サポート (i.s. `suspending functions`, 上で書いた物);
 - Kotlin Standard Library の 低レベルコアAPI
 - 直接ユーザーコードに現れる high-level APIs

### Low-level API: `kotlin.coroutines` 

ローレベルAPIは比較的小さい。高レベルAPIを作ること以外に使われるべきでない。２つのパッケージからなって居る。
- [`kotlin.coroutines.experimental`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/index.html) 主な型とプリミティブがある。例えば:
  -- [`createCoroutine()`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/create-coroutine.html),
  -- [`startCoroutine()`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/start-coroutine.html),
  -- [`suspendCoroutine()`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/suspend-coroutine.html);
- [`kotlin.coroutines.experimental.intrinsics`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental.intrinsics/index.html) 同じく低レベルの命令。例えば [`suspendCoroutineOrReturn`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental.intrinsics/suspend-coroutine-or-return.html).
 
これらの API の更に詳しい用法は [here](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md).

### Generators API in `kotlin.coroutines`
  
`kotlin.coroutines.experimental` のうち、"application-level" の関数は以下の二つ
- [`buildSequence()`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/build-sequence.html)
- [`buildIterator()`](/api/latest/jvm/stdlib/kotlin.coroutines.experimental/build-iterator.html)

これらはシーケンスとも関係があるので、 `kotlin-stdlib` の一部として公開されている。実際、これらの関数が _generator_ を実装している。
 
``` kotlin
import kotlin.coroutines.experimental.*

fun main(args: Array<String>) {
//sampleStart
    val fibonacciSeq = buildSequence {
        var a = 0
        var b = 1
        
        yield(1)
        
        while (true) {
            yield(a + b)
            
            val tmp = a + b
            a = b
            b = tmp
        }
    }
//sampleEnd

    // Print the first five Fibonacci numbers
    println(fibonacciSeq.take(8).toList())
}
```

この generates は `yield()` function を呼ぶことで、遅延評価で、潜在的に無限のフィボナッチ数列を生成している。シーケンスをイテレーションするときに、次の番号が生成される。すなわち、我々はどんな有限のリストもこのシーケンスから取り出す事ができる。そして、コルーチンはこれを実用的に実施するのに十分簡単な手段となっている。

このようなシーケンスの真の遅延評価のデモをするために、ビルドシーケンス内で、いくつかデバッグアウトプットを実施する事ができる。

``` kotlin
import kotlin.coroutines.experimental.*

fun main(args: Array<String>) {
//sampleStart
    val lazySeq = buildSequence {
        print("START ")
        for (i in 1..5) {
            yield(i)
            print("STEP ")
        }
        print("END")
    }

    // Print the first three elements of the sequence
    lazySeq.take(3).forEach { print("$it ") }
//sampleEnd
}
```

このコードを実行すると最初の３要素が print される。数字は `STEP` と交互に表示される。これは、処理が遅延で行われたことの例である。

collection または sequence の数値をまとめて評価するために `yieldAll()` 関数が使える:

``` kotlin
import kotlin.coroutines.experimental.*

fun main(args: Array<String>) {
//sampleStart
    val lazySeq = buildSequence {
        yield(0)
        yieldAll(1..10) 
    }

    lazySeq.forEach { print("$it ") }
//sampleEnd
}
```


`buildIterator()` も `buildSequence()` と同じような処理をする, ただし返すのは遅延評価のイテレーターである。

`SequenceBuilder` class (that bears the `@RestrictsSuspension` annotation described [above](#restrictssuspension-annotation)に対するサスペンディングエクステンションを書くことで、`buildSequence()` に custom yielding logic を追加できる :

``` kotlin
import kotlin.coroutines.experimental.*

//sampleStart
suspend fun SequenceBuilder<Int>.yieldIfOdd(x: Int) {
    if (x % 2 != 0) yield(x)
}

val lazySeq = buildSequence {
    for (i in 1..10) yieldIfOdd(i)
}
//sampleEnd

fun main(args: Array<String>) {
    lazySeq.forEach { print("$it ") }
}
```

  
### 他の高レベル API: `kotlinx.coroutines`


コルーチンに関連して core API だけが Kotlin Standard Library で利用可能。

ほとんどのコルーチンを基本にしたアプリケーションレベル API は他のライブラリとしてリリースされている: [`kotlinx.coroutines`](https://github.com/Kotlin/kotlinx.coroutines).このライブラリは以下をカバー
 * プラットフォーム非依存の非同期プログラミングを可能にする `kotlinx-coroutines-core`:
   * このモジュールは、Go-like な `channels` を提供。`channel` は `select` および他の便利なプリミティブを用意,
   * [`kotlinx-coroutines-core`の包括的ガイド](https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md);
 * JDK8 の `CompletableFuture` のための API: `kotlinx-coroutines-jdk8`;
 * JDK7 以上の Non-blocking IO (NIO) のための API: `kotlinx-coroutines-nio`;
 * Support for Swing (`kotlinx-coroutines-swing`) and JavaFx (`kotlinx-coroutines-javafx`);
 * RxJava サポート: `kotlinx-coroutines-rx`.
 
これらのライブラリは、共通処理を簡易に行うための便利なAPI群を提供し、また、コルーチンを基本にしたライブラリを提供するための end-to-end の例にもなっている。