programming extensions docs c# .net reactive-programming system.reactive ienumerable

c# - extensions - ¿Cuál es la diferencia entre las estructuras basadas en inserción y basadas en extracción como IEnumerable<T> y IObservable<T>



rx python (4)

Por favor, de una manera normal y humana, explícame la diferencia.

OK, vamos a hacer unas tostadas. Esa es la cosa humana más normal que hago.

Basado en pull

// 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.

Basado en empuje

// 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.

Desea obtener un resultado, llamar a una función y no hacer nada más hasta que la función regrese.

Si quiere que le envíen un resultado, llamará a una función asíncrona y esperará el resultado. Cuando el resultado está disponible, se inserta en la devolución de llamada, que reanuda el método donde debe estar.

IEnumerable<T> es solo una secuencia de tirones; llama a MoveNext cada vez que quiere obtener un resultado y obtiene una T IObservable<T> es solo una secuencia de pulsos; registra una devolución de llamada, y se llama cada vez que hay una nueva T disponible.

Dicho de otra manera: IEnumerable<T> es lógicamente una secuencia de invocaciones de Func<T> . IObservable<T> es lógicamente una secuencia de continuaciones de Task<T> . No dejes que el hecho de que sean secuencias te confunda; eso es incidental La idea fundamental es que las funciones son síncronas; los llamas y obtienes un resultado sincrónicamente ; Si toma un tiempo, espere. Las tareas son asíncronas; los inicia y obtiene el resultado de forma asíncrona cuando está disponible.

Esta idea existió en C # antes de IObservable y await . Otra forma de verlo es: la función pull-pull es como las llamadas a funciones, la función push-like es como los controladores de eventos. Una llamada de función normal, la llamas cuando quieres algo. Un controlador de eventos, te llama cuando algo sucede. Los eventos son cómo el lenguaje C # representa el patrón del observador . Pero los eventos siempre forman lógicamente una secuencia , por lo que tiene sentido poder manipular una secuencia de elementos empujados de la misma manera que manipulamos una secuencia de elementos extraídos. Y por lo tanto, IObservable fue inventado.

En cada charla técnica, o en cada publicación de blog que he leído sobre IEnumerable y IObservable , leí eso, IEnumerable es una estructura basada en pull e IObservable es una estructura basada en push.

He leído que con IObservable tenemos llamadas asíncronas, donde nada está bloqueado y todo está basado en push.

Pero pero pero...

¿Qué significa realmente? Basado en empuje y basado en pull

En mi opinión, en IEnumerable también podemos insertar datos en la estructura y también extraer datos de ellos, realmente he perdido en esos términos técnicos e ideas.

Por favor, de una manera normal y humana, explícame la diferencia entre esas dos estructuras y la diferencia entre las estructuras basadas en empuje y las basadas en tracción.

Gracias.


Un hombre entra a una tienda de comestibles y le pregunta al tendero si tiene huevos. "Sí", dice el tendero. "¿Puedo tener algo?" pregunta el hombre. Y el tendero le da unos huevos al hombre. "¿Tienes más?" pregunta el hombre. "Sí", dice el tendero. "¿Puedo tener algo?" pregunta el hombre. Y el tendero le da unos huevos al hombre. "¿Tienes más?" pregunta el hombre. "No", dice el tendero. El hombre se va.

Eso es basado en el tirón. El hombre siguió "tirando" los huevos del comerciante hasta que no quedara ninguno.

Un hombre entra a una tienda de comestibles y le pregunta al comerciante si puede entregar los huevos y, si es así, puede entregarlos cada vez que pueda obtenerlos. "Sí", dice el tendero. El hombre se va. En pocos días llegan algunos huevos. Unos días más tarde llegan algunos huevos. Luego el hombre llama al comerciante y le pide que detenga las entregas. No llegan más huevos.

Eso es basado en empuje. El hombre no espera que el tendero le dé los huevos. El hombre hace otra cosa y el tendero "empuja" los huevos al hombre.


Además de las excelentes respuestas anteriores, también ofrecería lo siguiente:

  • ''IEnumerable'' que significa ''enumerable'' se confunde implícitamente con ''pull based'' en el modelo conceptual de .NET framework. Se pretende que signifique "le permite obtener un enumerador, lo que le permite obtener el siguiente valor"
  • Pero también tenemos IAsyncEnumerable.
  • Matemáticamente, enumerable solo significa "contable", es decir, un conjunto contable.
  • Los observables también pueden ser contables, en el sentido de que un observable puede representar un conjunto de eventos discretos.

La denominación es confusa y, en mi opinión, representan mal los conceptos que pretenden. Por ejemplo, en el mundo Java, IEnumerable es iterable, que está más cerca de la intención en .NET.

Creo que es más simple imaginar que IEnumerable y el LINQ se construyan a su alrededor como " Consígame algunos datos de alguna fuente y filtre / agrupe de esta forma ..." mientras que los Observables pueden considerarse como flujos entrantes a los que puede reaccionar. No creo que sea necesariamente útil pensar en observables como continuaciones.


Suponiendo un servidor (lógico) y un cliente, ¿quién determina cuándo se entregan los datos, el servidor o el cliente?

Basado en extracción describe un esquema de ejecución del cliente: los clientes realizan solicitudes y los datos se entregan inmediatamente. Basado en empuje describe un esquema de ejecución de servidor: los clientes pueden conectarse a un flujo de empuje (IObservable), pero no pueden exigir datos, los obtienen cuando el servidor tiene ganas de darlos.

Una forma canónica de extracción sería una consulta de base de datos: envía una solicitud al servidor y el servidor responde con una colección de elementos. Una versión canónica de push sería una aplicación de chat: el cliente de chat no puede "solicitar" nuevos datos de conversación, el servidor le dirá cuándo la otra persona ha dicho algo.