La mayoría del procesamiento de datos se puede prever como una tubería de componentes, la salida de una alimentación en la entrada de otra. Una canalización de procesamiento típica es:marcos para representar el procesamiento de datos como una tubería
reader | handler | writer
Como una lámina para el inicio de esta discusión, vamos a considerar una implementación orientada a objetos de esta tubería, donde cada segmento es un objeto. El objeto handler
contiene referencias tanto a los reader
y writer
objetos y tiene un método run
que se parece a:
define handler.run:
while (reader.has_next) {
data = reader.next
output = ...some function of data...
writer.put(output)
}
Esquemáticamente las dependencias son:
reader <- handler -> writer
Ahora supongamos que quiero interponer un nuevo segmento de la tubería entre el lector y el controlador:
reader | tweaker | handler | writer
De nuevo, en este OO implementación, tweaker
sería una envoltura alrededor del objeto reader
y los métodos tweaker
podría ser algo como (en algún código de pseudo-imperativo):
define tweaker.has_next:
return reader.has_next
define tweaker.next:
value = reader.next
result = ...some function of value...
return result
estoy descubriendo que esto no es una abstracción muy componibles. Algunos temas son:
tweaker
sólo se puede utilizar en el lado izquierdo dehandler
, es decir, que no se puede utilizar la aplicación anterior detweaker
para formar este gasoducto:lector | manejador | tweaker | escritor
me gustaría explotar la propiedad asociativa de tuberías, de modo que este gasoducto:
lector | manejador | escritor
podría expresarse como:
reader | p
donde p
es la tubería handler | writer
. En esta implementación OO tendría que crear una instancia parcialmente el objeto handler
- algo de una reexpresión de (1), los objetos tienen que saber si los datos de "atracción" de "empuje" o.
Estoy buscando un marco (no necesariamente OO) para crear canalizaciones de procesamiento de datos que resuelva estos problemas.
Lo he etiquetado con Haskell
y functional programming
porque creo que los conceptos de programación funcional pueden ser útiles aquí.
Como objetivo, sería agradable ser capaz de crear una tubería así:
handler1
/ \
reader | partition writer
\ /
handler2
Por alguna perspectiva, las del shell Unix resuelve muchos de estos problemas con las siguientes decisiones de implementación:
componentes de tuberías se ejecutan de forma asíncrona en procesos separados
canalizar objetos median pasar datos entre "empujadores" y "pulle rs "; es decir, bloquean a los escritores que escriben datos demasiado rápido y los lectores que intentan leer demasiado rápido.
Se utilizan conectores especiales y
<
>
para conectar componentes pasivos (es decir, archivos) a la tubería
Estoy especialmente interesado en los enfoques que no utilizan roscado o de paso de mensajes entre los agentes. Tal vez esa sea la mejor manera de hacerlo, pero me gustaría evitar el enhebrado si es posible.
Gracias!
Eche un vistazo a http://www.haskell.org/arrows –
Quizás le gustaría generar algunos hilos, uno para cada lector, tweaker, manejador y escritor, y comunicarse a través de ['Chan's ] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent-Chan.html)? Aunque no estoy 100% seguro de entender lo que es la pregunta de nivel superior ... –
Hasta ahora, el último diagrama se ve como 'reader >>> partition >>> handler1 *** handler2 >>> writer', pero probablemente haya algunos requisitos que lo hagan más complicado. –