programming asynchronous clojure reactive-programming frp core.async

asynchronous - reactive programming java



Comparando core.async y Functional Reactive Programming(+ Rx) (5)

Parece que estoy un poco confundido cuando comparo el core.async de Clojure con las llamadas Reactive Extensions (Rx) y FRP en general. Parecen abordar un problema similar de asincronicidad, por lo que me pregunto cuáles son las principales diferencias y en qué casos se prefiere uno sobre el otro. ¿Alguien puede explicar?

EDITAR: Para alentar más respuestas en profundidad, quiero hacer la pregunta más específica:

  1. Core.async me permite escribir código de aspecto síncrono. Sin embargo, como entiendo, FRP solo necesita un nivel de devoluciones de llamada anidadas (todas las funciones que manejan la lógica se pasan como argumentos a la API de FRP). Parece que ambos enfoques hacen que las pirámides de devolución de llamada sean innecesarias. Es verdad que en JS tengo que escribir la function() {...} muchas veces, pero el problema principal, las devoluciones de llamada anidadas , también se ha eliminado en FRP. ¿Lo entiendo bien?

  2. " FRP compila la comunicación de mensajes con flujo de control" ¿Puede (alguien) dar una explicación más específica?

  3. ¿No puedo pasar los puntos finales observables de FRP de la misma manera que paso los canales?

En general, entiendo de dónde vienen ambos enfoques históricamente y he probado algunos tutoriales en ambos. Sin embargo, parezco estar "paralizado" por la no evidencia de las diferencias. ¿Hay algún ejemplo de un código que sería difícil de escribir en uno de estos y fácil de usar en el otro ? ¿Y cuál es la razón arquitectónica de eso?


Al menos una de las principales diferencias principales, y, creo, qué Richment por "[FRP] compila la comunicación de mensajes con flujo de control", es la siguiente.

Las devoluciones de llamada son código que se ejecuta. Y esa ejecución tiene que suceder en algún hilo en algún momento. A menudo, el momento es cuando ocurre el evento, y el hilo es el hilo que nota / produce el evento. Si el productor en cambio pone un mensaje en un canal, puede consumir el mensaje cuando lo desee, en el hilo que desee. Por lo tanto, las devoluciones de llamadas, que son esencialmente una forma de comunicación, completan la comunicación con flujo de control dictando cuándo y dónde se está ejecutando el código de devolución de llamada. Si tiene que usar devoluciones de llamada por cualquier razón, simplemente úselos para poner un mensaje en una cola / canal y usted está de nuevo en la pista.

Debido a que core.async es menos complejo, debe preferirse siempre que no haya una buena razón para usar las alternativas.


Creo que el principal problema es que su suposición sobre el problema abordado no es del todo así, ya que ninguno de ellos aborda el "problema" de asincronicidad .

Las abstracciones

FRP idea principal de FRP es la propagación del cambio, piense en lograr lo mismo que Excel, donde define las celdas que dependen una de la otra en cascada , y cuando una celda cambia, todas las celdas dependientes de la cascada se recalculan.

core.async idea principal de core.async es la descomposición de los sistemas, pensar como separar las preocupaciones usando una queue en medio de diferentes procesos, en el caso core.async en lugar de en las colas, tienes canales pero obtienes la idea.

Por lo tanto, eliminar el código piramidal no es el objetivo de ninguna de las tecnologías, y operan en diferentes capas de abstracción.

Acerca de completar el flujo de control

La idea de completar la comunicación y el control de flujo se toma de la publicación asincrónica principal original .

Si bien existen varios mecanismos para hacer que los eventos / devoluciones de llamada sean más limpios (FRP, Rx / Observables), no cambian su naturaleza fundamental, que es que en un evento se ejecuta una cantidad arbitraria de otro código, posiblemente en el mismo hilo, lo que lleva a advertencias tales como "no haga demasiado trabajo en su controlador" y frases como "infierno de devolución de llamada".

Por otra parte, si tiene un código de dominio empresarial dentro de un controlador de eventos, ha compilado el proceso de eventos X con qué hacer cuando sucede X.

Que es lo que core.async aborda, ya que la introducción de una cola / canal en el medio, ayuda a una mejor separación de las preocupaciones.

Implementación

Todas sus preguntas sobre devoluciones de llamadas y el paso de puntos finales observables como parámetros son solo preguntas de implementación, realmente depende de la implementación de Rx y API.

Si nos fijamos en los componentes reutilizables Reacciona , realmente no tienes mucho de un infierno de devolución de llamada para ser visto, y tienes la idea de pasar elementos observables.

Pensamientos finales

Incluso si Rx se puede usar para modelar cualquier flujo de datos, se usa más comúnmente para UI Rendering a-la Excel, para simplificar cómo se actualiza la vista cuando cambia el modelo.

Por otro lado, Core.Async se puede usar para modelar la separación de preocupaciones cuando dos subsistemas se comunican entre sí (el mismo escenario de uso como colas), usándolo en la idea principal de la cadena de representación de UI es separar:

  • Generación y procesamiento de eventos del lado del servidor
  • Cómo ese evento afecta tu modelo

De modo que puede tener core.async y FRP juntos, ya que core.async separará las preocupaciones, y FRP definirá su flujo de datos en cascada una vez que se actualice su modelo.


EDITAR:

Para responder tu pregunta:

  1. Sí, muchas veces, las devoluciones de llamadas se pueden eliminar, por ejemplo con la lógica de reintento, distinctUntilChanged y muchas otras cosas como:

    var obs = getJSON(''story.json'').retry(3);

    var obs = Rx.Observable.fromEvent(document, ''keyup'').distinctUntilChanged();

  2. No estoy seguro de a qué se refiere esto al hacerlo más complejo con el control de flujo.

  3. Sí, puedes pasar alrededor de un objeto como lo harías con un canal, como con el objeto siguiente.

Por ejemplo, puede tener un comportamiento similar a un canal aquí utilizando RxJS con un ReplaySubject :

var channel = new Rx.ReplaySubject(); // Send three observables down the chain to subscribe to channel.onNext(Rx.Observable.timer(0, 250).map(function () { return 1; })); channel.onNext(Rx.Observable.timer(0, 1000).map(function () { return 2; })); channel.onNext(Rx.Observable.timer(0, 1500).map(function () { return 3; })); // Now pass the channel around anywhere! processChannel(channel);

Para hacerlo un poco más concreto, compara el código de la publicación de David Nolen here con un ejemplo de RXJS FRP here


Hay una publicación aquí que compara FRP con CSP en un conjunto limitado de ejemplos (que, sin embargo, significaba demostrar los beneficios de CSP), con una conclusión al final: http://potetm.github.io/2014/01/07/frp.html


Clojure core.async es un puerto de go bloques del lenguaje Go . El concepto fundamental son los canales que representan la comunicación asíncrona entre hilos.

El objetivo es poder escribir bloques de código secuencial de aspecto normal que accedan a los canales para obtener entradas, y esto se traduce a la perfección en una máquina de estados que CSP traducción de CSP por usted.

Contraste con FRP, que sigue siendo fundamentalmente sobre devoluciones de llamada, y compila la comunicación de mensajes con flujo de control. core.async elimina las retrollamadas de tu código por completo, y separa el flujo de control de la transmisión de mensajes. Además, en FRP, un canal no es un objeto de primera clase (es decir, no puede enviar un canal de FRP como un valor en un canal de FRP).