2011-08-27 30 views
6

Soy nuevo en Rx. Puedo ver algunos beneficios reales de utilizar caliente observables, sin embargo poco me pidieron la pregunta sobre cuál era la diferencia entre un observable en frío y un enumerable equivalente (véase el siguiente fragmento de código) ...Diferencia entre observable en frío en RX y normal Enumerable

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

Puede alguien explicar muy simplemente cuál es la diferencia entre los dos y qué beneficio obtendría del observable frío versus el enumerable.

Respuesta

15

Existen varias diferencias entre los dos.

Quién controla el 'enumeración'

Con la observable (caliente o frío), es el observable 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.

de flujo Código

enumerables de procesamiento normalmente se realiza en un bucle para cada uno (o en ocasiones conseguir el empadronador y el uso de un bucle while). Su código normalmente 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. Existen algunos operadores de bloqueo para observables, como First, pero son la excepción y no la regla para el uso normal.

Tome este ejemplo de programa trivial como ejemplo. Con el enumerable, todos los valores se escriben antes de continuar con la siguiente parte. Los valores de lo observable, sin embargo, no están garantizados para escribirse alguna vez. Cuantos valores se escriban antes de que termine el programa es más o menos 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 
} 

asíncrono procesa

Al igual que usted tiene que escribir código adicional para bloquear y esperar a que un observable, escribiendo un IEnumerable que utiliza un proceso asíncrono requiere un trabajo extra. Aquí es donde la diferencia entre los dos realmente entra en juego.

Por ejemplo, en una aplicación en la que estoy trabajando actualmente, debo buscar dispositivos que puedan estar conectados a un puerto en serie. Un IObservable es una buena opción para esto porque me permite hacer una devolución de llamada y notificar a la aplicación para cada dispositivo cada vez que lo encuentro sin tener que bloquear y cuando la operación se completa. Este observable califica como cold 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 en frío, comienzo el trabajo antes de una suscripción, pero no se pierden datos porque se almacena en un sujeto de repetición). Sin embargo, no tendría mucho sentido para mí convertirlo en un Enumerable debido a la asincrónica naturaleza.

+0

Gracias Gideon ... gran idea. –

6

¿Casi todos los Enumerables que usted está acostumbrado son Enumerables "fríos"? ¿Por qué? Porque si tuvieras que vencer dos veces a Enumerable.Range, obtendrías dos veces los números.

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

Para Rx, un Cold Observable significa que cada vez que llame a Subscribe (el equivalente a ForEach en Rx), recibirá una nueva lista de cosas. Los Hot Observables como FromEvent no te ofrecerán una nueva secuencia de eventos cada vez que suscribas, sino que se tratará de otra conexión a la misma secuencia 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)); 
Cuestiones relacionadas