1. ホーム
  2. kotlin

[解決済み] KotlinのコルーチンはRxKotlinよりどう優れているか?

2023-01-29 15:04:47

質問

なぜKotlinのコルーチンを使いたいのでしょうか?

RxKotlinのライブラリの方が汎用性が高そうだから。 それに比べてKotlinのコルーチンは大幅にパワー不足で、使うのが面倒そうです。

私がコルーチンについて考える根拠は Andrey Breslav (JetBrains)によるこのデザイントークに基づきます。

講演のスライドショーは でアクセスできます。


EDIT (@hotkeyさんに感謝)。

コルーチンの現状に関するより良いソース はこちらです。

どのように解決するのですか?

免責事項です。 Coroutinesは現在、Rxのものに非常に似たフローAPIを持っているので、この答えの一部は無関係です。最新の回答が必要な場合は、最後の編集にジャンプしてください。

Rxには、Observableパターンと、それらを操作、変換、結合するための強固な演算子セットの2つの部分があります。Observableパターンは、それ自体では、多くのことを行うことはできません。コルーチンも同じで、非同期を扱うためのパラダイムに過ぎない。コールバック、Observable、コルーチンの長所と短所を比較することはできますが、パラダイムとフル機能のライブラリーを比較することはできません。それは、言語とフレームワークを比較するようなものです。

KotlinのコルーチンはRxKotlinよりどう優れているのか?コルーチンはまだ使っていませんが、C#のasync/waitに似ていますね。コルーチンはC#のasync/waitと同じようなもので、シーケンシャルなコードを書くだけで、同期的なコードを書くのと同じように、非同期的に実行される。そのほうがわかりやすい。

なぜkotlinのコルーチンを使いたいのか?自分自身で答えましょう。私はイベント駆動型アーキテクチャを好むので、ほとんどの場合、Rxにこだわります。しかし、私がシーケンシャルなコードを書いていて、途中で非同期メソッドを呼び出す必要がある状況が発生した場合、私は喜んでその状態を維持し、すべてをObservableで包むのを避けるためにコルーチンを活用します。

編集 : コルーチンを使うようになったので、更新の時期が来たようです。

RxKotlinはKotlinでRxJavaを使用するための構文上の糖分です。コルーチンはRxJavaよりも低レバーでより一般的な概念であり、他のユースケースを提供します。とはいえ、RxJavaとコルーチンを比較できるようなユースケースが1つあります ( channel ) を比較できる1つのユースケースがあります。それは、非同期でデータを受け渡すことです。ここでは、コルーチンはRxJavaに対して明らかに有利です。

コルーチンはリソースを扱うのに優れている

  • RxJavaでは、計算をスケジューラに割り当てることができますが subscribeOn()ObserveOn() は紛らわしい。すべてのコルーチンは、スレッドコンテキストを与えられ、親コンテキストに戻ります。チャネルでは、プロデューサとコンシューマの両方が自分のコンテキストで実行されます。コルーチンはスレッドやスレッドプールへの影響についてより直感的です。
  • コルーチンは、計算がいつ行われるかについて、より多くの制御を与える。例えば、手渡しで ( yield ) 、優先順位をつける ( select ) 、並列化 (複数の producer / actor について channel ) またはロックリソース ( Mutex ) を指定します。サーバ上(RxJavaが最初に登場した場所)では重要ではないかもしれませんが、リソースが限られた環境では、このレベルの制御が必要かもしれません。
  • その反応的な性質のために、背圧はRxJavaにうまくフィットしません。もう一方では send() は、チャネルの容量に達したときに一時停止するサスペンシブな関数です。これは、本質的に与えられたバックプレッシャーのうちです。また offer() をチャネルに渡すこともできます。この場合、呼び出しは決してサスペンドせず、代わりに false を返し、効果的に onBackpressureDrop() をRxJavaから再現しています。あるいは、独自のカスタム背圧ロジックを書くこともできます。これはコルーチンを使えば難しくありませんし、特にRxJavaで同じことをするのに比べれば。

なぜKotlinのコルーチンを使いたいのか」という2つ目の質問に対する答えです。コルーチンは、バックグラウンドスレッドや、コルーチンを使用するアプリケーションの完璧な置き換えです。 AsyncTask (アンドロイド)です。と同じくらい簡単です。 launch { someBlockingFunction() } . もちろん、RxJavaでもこれを実現することができます。 SchedulersCompletable を使うかもしれません。RxJavaの特徴であるObserverパターンと演算子は使わない(あるいはほとんど使わない)と思いますが、これはこの作業がRxJavaの範囲外であることを示すヒントです。RxJavaの複雑さ(ここでは無駄な税金)は、あなたのコードをCoroutineのバージョンよりも冗長にし、クリーンでなくします。

読みやすさは重要です。この点で、RxJavaとコルーチンのアプローチは大きく異なります。コルーチンはRxJavaよりシンプルです。もし、あなたが map() , flatmap() といった関数型反応性プログラミングでは、コルーチンの操作はより簡単で、基本的な命令で済みます。 for , if , try/catch ... しかし、個人的には、コルーチンのコードは非自明なタスクでは理解しにくいと感じています。特に、RxJavaでは演算子の連鎖によってすべての処理が一直線になるのに対し、コルーチンは入れ子やインデントが多くなります。関数型プログラミングは、処理をより明示的にします。さらに、RxJavaは豊富な(いや、豊富すぎる)演算子セットの中からいくつかの標準的な演算子を使って複雑な変換を解決することができます。RxJavaは、多くの組み合わせと変換を必要とする複雑なデータフローを持つときに輝きます。

これらの考察が、あなたのニーズに応じて適切なツールを選択する助けになることを願っています。

編集する。 Coroutineは現在、Rxと非常によく似たAPIであるflowを持っています。

Coroutine にはRxに非常によく似たAPIがあります。

Coroutinesの中核は並行処理デザインパターンであり、アドオンライブラリの1つはRxに類似したストリームAPIである。明らかに、CoroutinesはRxよりはるかに広い範囲を持ち、RxにできないことがCoroutinesにできることがたくさんあります。しかし、通常、私がプロジェクトでコルーチンを使用する場合、それは1つの理由に集約されます。

コルーチンはコードからコールバックを取り除くのに優れている。

私は可読性を損なうようなコールバックは使わないようにしています。コルーチンは非同期コードをシンプルに、そして簡単に書くことができます。サスペンドキーワードを活用することで、あなたのコードは同期的なもののように見えます。

Rxがコールバックを置き換えるのと同じ目的でプロジェクトで使われているのを見たことがありますが、リアクティブパターンにコミットするためにアーキテクチャを変更する予定がない場合、Rxは負担になるでしょう。このインターフェイスを考えてみましょう。

interface Foo {
   fun bar(callback: Callback)
}

Coroutineに相当するものはより明示的で、戻り値の型と、非同期処理であることを示すキーワードsuspendがあります。

interface Foo {
   suspend fun bar: Result
}

しかし、Rx相当には問題がある。

interface Foo {
   fun bar: Single<Result>
}

コールバックまたはコルーチン版でbar()を呼び出すと、計算がトリガーされます。Rx版では、自由にトリガーできる計算の表現が得られます。Rxバージョンでは、自由にトリガーできる計算の表現が得られます。Singleにサブスクライブしてからbar()を呼び出す必要があるのです。通常、大きな問題ではありませんが、初心者には少しわかりにくく、微妙な問題につながる可能性があります。

そのような問題の一例として、コールバックのbar関数がこのように実装されているとします。

fun bar(callback: Callback) {
   setCallback(callback)
   refreshData()
}

適切に移植しないと、サブスクリプション時ではなく bar() 関数内で refreshData() が呼び出されるため、一度だけトリガーされる Single が出来上がってしまうでしょう。初心者のミスですが、Rxはコールバックの置き換え以上のものであり、多くの開発者がRxを理解するのに苦労しています。

もしあなたの目的が非同期タスクをコールバックからより良いパラダイムに変換することであるなら、Rxがいくらかの複雑さを追加するのに対して、コルーチンは完璧にフィットします。