Diferencia entre frío observable en RX y normal Enumerable

Soy nuevo en Rx. Puedo ver algunos beneficios reales de usar Hot Observables, sin embargo, recientemente me hicieron la pregunta sobre cuál era la diferencia entre un observable frío y un enumerable equivalente (vea el fragmento de código a continuación) ...

    var resRx = Observable.Range(1, 10);
    var resOb = Enumerable.Range(1, 10);

¿Alguien puede explicar de manera muy simple cuál es la diferencia entre los dos y qué beneficio obtendría del frío observable frente al enumerable?

preguntado el 27 de agosto de 11 a las 14:08

2 Respuestas

Hay varias diferencias entre los dos.

Quién controla la 'enumeración'

Con lo observable (caliente o frío), es lo observable lo que determina cuándo y en qué hilo se devuelven los valores. Un enumerable, por otro lado, obtiene cada valor cuando lo solicita y se procesa en el hilo que solicita la enumeración.

Flujo de código

El procesamiento de enumerables se realiza típicamente en un ciclo para cada ciclo (u ocasionalmente se obtiene el enumerador y se usa un ciclo while). Normalmente, su código procesará todos los valores antes de continuar. Los observables requieren una devolución de llamada. Bloquear la ejecución adicional de su código (por ejemplo, para evitar salir de una aplicación de consola) requiere código adicional de su parte. Hay algunos operadores de bloqueo para observables, como First, pero son la excepción y no la regla para el uso normal.

Tome este programa de muestra trivial como ejemplo. Con el enumerable, todos los valores se escriben antes de continuar con la siguiente parte. Sin embargo, no se garantiza que los valores de lo observable se escriban nunca. La cantidad de valores que se escriben antes de que finalice el programa es prácticamente una condición de carrera.

static void Main(string[] args)
{
    var xs = Enumerable.Range(1, 10);
    foreach (var x in xs)
    {
        Console.WriteLine(x);
    }
    //at this point, all values have been written

    var ys = Observable.Range(1, 10);
    ys.Subscribe(y => Console.WriteLine(y));
    //at this point, no values have been written (in general)

    //either add a Console.ReadKey or some sort of wait handle that
    //is set in the OnCompleted of the observer to get values
}

Procesos asincrónicos

Al igual que tiene que escribir código adicional para bloquear y esperar un observable, escribir un IEnumerable que usa un proceso asincrónico requiere un trabajo adicional. Aquí es donde realmente entra en juego la diferencia entre los dos.

Por ejemplo, en una aplicación en la que estoy trabajando actualmente, necesito buscar dispositivos que puedan estar conectados a un puerto serie. Un IObservable es una buena opción para esto porque me permite recibir una devolución de llamada y notificar a la aplicación para cada dispositivo cada vez que lo encuentre sin tener que bloquearlo y cuando se complete la operación. Este observable califica como un frío observable porque no enviará datos a menos que haya un suscriptor, y cada suscripción obtiene todos los resultados. (A diferencia del típico observable frío, comienzo el trabajo antes de una suscripción, pero no se pierden datos porque se almacenan en un sujeto de repetición). Sin embargo, no tendría mucho sentido para mí convertirlo en un Enumerable debido al asincrónico naturaleza.

Respondido 27 ago 11, 20:08

Gracias Gideon ... gran conocimiento. - Mark Pearl

¿Casi todos los Enumerables a los que está acostumbrado son Enumerables "Fríos"? ¿Por qué? Porque si tuvieras que ForEach sobre el Enumerable.Range dos veces, obtendrías el doble de los números.

Si Enumerable.Range fuera un Hot Enumerable, solo le daría la lista una vez y el segundo ForEach estaría vacío.

Para Rx, un Cold Observable significa que cada vez que llame a Subscribe (el equivalente de ForEach en Rx), recibirá una nueva lista de cosas. Los Hot Observables como FromEvent no le brindarán un nuevo flujo de eventos cada vez que se suscriba, solo será otra conexión al mismo flujo de eventos.

Sin embargo, ¿cuál es la ventaja de Rx aquí? Poder convertir ese rango en solicitudes asíncronas:

IObservable<Image> fetchImageByIndex(int imageIndexOnSite);

Observable.Range(0, 10)
    .SelectMany(x => fetchImageByIndex(x)) 
    .Subscribe(image => saveImageToDisk(image));

Respondido 28 ago 11, 03:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.