web-dev-qa-db-ja.com

IEnumerable <T>やIObservable <T>のようなプッシュベースの構造とプルベースの構造の違いは何ですか

すべての技術的な話、またはすべてのブログ投稿で、私はIEnumerableおよびIObservableについて読んだことがありますIEnumerableはプルベースの構造で、IObservableはプッシュベースの構造です。

私はそれをIObservableで読みましたが、何もブロックされておらず、すべてがプッシュベースの非同期呼び出しがあります。

しかし、しかし、しかし...

それはどういう意味ですか? Pushベースおよびpullベース

IEnumerableの私の意見では、データを構造体にプッシュしたり、構造体からデータをプルしたりすることもできるので、その技術用語とアイデアを本当に失っています。

通常の人間の方法で、その2つの構造の違いと、プッシュベースの構造とプルベースの構造の違いについて説明してください。

ありがとう。

21

通常の人間の方法で違いを説明してください

はい、トーストを作りましょう。それが私がする最も普通の人間の行為です。

プルベース:

// I want some toast.  I will pull it out of the toaster when it is done.
// I will do nothing until the toast is available.
Toast t = toaster.MakeToast();
t.AddJam();
// Yum.

プッシュベース:

// I want some toast.  But it might take a while and I can do more work
// while I am waiting:
Task<Toast> task = toaster.MakeToastAsync();
Toast t = await task;
// await returns to the caller if the toast is not ready, and assigns
// a callback. When the toast is ready, the callback causes this method
// to start again from this point:
t.AddJam();
// Yum.

結果を取得したい場合は、関数を呼び出し、関数が戻るまで他に何もしません。

結果をプッシュしたい場合は、非同期関数を呼び出して結果を待ちます。結果が利用可能になると、コールバックでプッシュされ、必要な場所でメソッドが再開されます。

IEnumerable<T>はプルのシーケンスにすぎません。結果を取得するたびにMoveNextを呼び出し、Tを取得します。 IObservable<T>は単なるプッシュのシーケンスです。コールバックを登録すると、新しいTが利用可能になるたびに呼び出されます。

言い換えると、IEnumerable<T>は論理的にはFunc<T>invocationsのシーケンスです。 IObservable<T>は論理的にはTask<T>continuationsのシーケンスです。それらがシーケンスであるという事実を混乱させないでください。それは付随的です。基本的な考え方は、関数は同期的であるということです。それらを呼び出して、結果を取得します同期的に;時間がかかる場合は、お待ちください。タスクは非同期です。あなたはそれらを開始し、それが利用可能になったときに結果を非同期で取得します.


このアイデアは、C#のIObservableおよびawaitより前に存在していました。もう1つの見方は、プルベースは関数呼び出しのようなもので、プッシュベースはイベントハンドラのようなものです。通常の関数呼び出し。何かが必要なときに呼び出します。イベントハンドラーは、何かが発生したときに呼び出します。 イベントは、C#言語自体がオブザーバーパターンを表す方法です。ただし、イベントは常に論理的にsequenceを形成するため、プッシュされたアイテムのシーケンスを、アイテムを引っ張った。したがって、IObservableが発明されました。

24
Eric Lippert

(論理)サーバーとクライアントを想定し、データの配信時期を決定するのはサーバーですか、クライアントですか?

プルベースはクライアント実行スキームを表します。クライアントはリクエストを行い、データはすぐに提供されます。プッシュベースはサーバー実行スキームを表します。クライアントはプッシュストリーム(IObservable)に接続できますが、データを要求することはできず、サーバーがデータを提供したいときにデータを取得します。

標準的な形式のプルはデータベースクエリです。サーバーにリクエストを送信すると、サーバーはアイテムのコレクションで応答します。標準的なバージョンのPushはチャットアプリになります。チャットクライアントは新しい会話データを「要求」できません。サーバーは、他の人が何かを言ったときに通知します。

4
Shlomo

男性が食料品店に足を踏み入れ、店主に卵があるかどうか尋ねます。 「はい」と店主は言います。 「いくつか持っていいですか?」男に尋ねる。そして店主はその男に卵を与えます。 「これ以上ありますか?」男に尋ねる。 「はい」と店主は言います。 「いくつか持っていいですか?」男に尋ねる。そして店主はその男に卵を与えます。 「これ以上ありますか?」男に尋ねる。 「いいえ」と店主は言う。男は去ります。

それはプルベースです。男は、何もなくなるまで店主から卵を「引っ張る」ようにします。

ある男が食料品店に足を運び、店主に卵を配達できるかどうか尋ねます。できれば卵を手に入れられるときはいつでも配達できます。 「はい」と店主は言います。男は去ります。数日でいくつかの卵が到着します。さらに数日後、いくつかの卵が到着します。それから男は店主に電話して配達を止めるように頼みます。これ以上卵は届きません。

それはプッシュベースです。男は店主が彼に卵を与えるのを待ちません。男は他のことをしに行き、店主は卵を男に「押し」ます。

2
Enigmativity

上記の素晴らしい答えに加えて、私は以下も提供します:

  • 「列挙可能」を意味する「IEnumerable」は、.NET Framework概念モデルの「プルベース」と暗黙的に混同されます。これは、「列挙子を取得できるようにします。これによりpull次の値が許可されます」
  • しかし、IAsyncEnumerableもあります。
  • 数学的には、列挙可能とは単に「可算」、つまり可算セットを意味します。
  • オブザーバブルは離散イベントのセットを表す場合があるという意味で、オブザーバブルもカウント可能です。

ネーミングは混乱しており、私の意見では、彼らが意図している概念をうまく表現できていません。たとえば、Java=の世界では、IEnumerableはIterableであり、.NETの意図に近いものです。

IEnumerableとその周りのLINQ構成を想像するのが最も簡単だと思います "あるソースからデータを取得し、このようにフィルター/グループ化します..."一方、Observableは、反応できる着信ストリームと考えることができます。オブザーバブルを継続として考えることは必ずしも有益ではないと思います。

1
Sentinel