2012-01-04 11 views
8

En su talk en la marca de 54:53 minutos, Rich Hickey está hablando sobre el uso de colas como un medio para desacoplar partes de programas dependientes. ¿Me puede dar un ejemplo sobre cómo deouple el siguiente fragmento de Java-pseudo-código con el fin de mejorar su diseño y/o flexibilidad:Programas de desacoplamiento usando colas

// Warning: Java-pseudo-code ahead 
class Job { 
    public void doRun(A a) { 
     saveObjectToDatabase(a); 

     B b = computeB(a); 
     saveObjectToDatabase(b); 

     C c = computeC(b); 
     logToFile(c); 
    } 
} 

saveObjectToDatabase y saveObjectToDatabase puede ser visto como un método con efectos secundarios , mientras que los resultados de computeB y computeC solo dependen de a.

Sé que esta pregunta es bastante vaga/amplia. Me gustaría tener una idea de cómo aprovechar los mecanismos de colas sin complicar enormemente mi programa y aún así asegurarme de que haga lo correcto en el orden correcto. Cualquier indicador en la dirección correcta es apreciado.

+0

No está muy claro. El ejemplo que muestra tiene un método independiente, que no utiliza ninguna dependencia externa. No hay nada que desacoplar ya que el Trabajo no está acoplado a nada. –

+0

Supongo que a @Matt le gustaría obtener diferentes hilos haciendo los métodos computeB() y computeC(), usando colas para mover unidades de trabajo entre los diferentes hilos. – Rich

+0

Consulte [Enterprise Integration Patterns] (http://www.eaipatterns.com/). – TrueWill

Respuesta

3

Bueno, no es un muy buen ejemplo, pero (en el diseño más simple) básicamente tendrías dos colas, y (dependiendo de la cantidad de datos involucrados) podrías omitir la base de datos.

Un primer proceso recibiría sus a objetos del "mundo exterior" y poner en cola en la cola 1. Un segundo proceso podría quitar de la cola de la cola de objetos 1, realice computeB, y poner en cola los resultados en la cola 2. Un tercer proceso haría dequeue los objetos de la cola 2, realice computeC, y registre el resultado o lo que sea.

función, como ya he dicho, de la cantidad de datos involucrados (y tal vez algunos otros factores) los "objetos" aprobadas en las colas pueden ser o bien sus reales a y b objetos o de lo contrario simplemente fichas/claves para encontrar el datos en la base de datos.

Las colas mismas podrían implementarse de varias maneras. Es posible implementar una cola con una base de datos, por ejemplo, aunque los detalles se vuelven un tanto complicados. Los "procesos" podrían ser tareas de Java dentro de un solo proceso de Java o podrían ser procesos de sistema operativo separados, posiblemente incluso en máquinas separadas.

Cuando usa "pipes" en Unix, está utilizando colas de esta manera.

1

Este es exactamente el principio utilizado por una biblioteca de Java que estoy usando. La idea es tener componentes asignados a tareas individuales en los programas (el registrador es un ejemplo perfecto). Ahora cada componente necesita ejecutarse independientemente de los demás, ya sea como un hilo como un controlador de eventos.

En el caso de un evento controlado, cada componente notifica los tipos de eventos \ mensajes que desea escuchar. Usted tiene un despachador que recoge los mensajes entrantes y los inserta en la cola de los receptores. El proceso del receptor, y eventualmente generar nuevos mensajes. Y etc ...

En su caso, algo como esto:

class SaveObjectHandler{ 
// 
void handle(Event e, Object o){ 
    if(e instanceof SaveEvent) 
     saveObjectToDatabase(o); 
} 

}; 

class TransformObject{ 
// 
void handle(Event e,Object o){ 
    if(e instanceof TransformEvent){ 
     B result = compute(o); 
     send(new SaveEvent(),result) 
    } 

} 

}; 

class Logger{ 

    void handle(Event e, Object o){ 
     if(o instanceof B) 
     //perform computeC 
     logEvent((B)o); 
    } 

}; 

};

La biblioteca en cuestión es SEDA.

0

Me temo que con métodos saveObject que tienen efectos colaterales no se puede desacoplar bien o al menos no fácilmente.

Pero digamos que necesita escribir rápidamente en la base de datos algunos objetos.Mi opinión es que la manera más rápida con Relational DB debería ser guardar los objetos en una cola por varios clientes y luego seleccionarlos por uno o dos escritores rápidos que envían los datos a la base de datos lo más rápido posible.

0

En aras de la exhaustividad, me gustaría añadir algo más de información a Hot Licks' respuesta:

que he estado haciendo más investigaciones sobre este tema y, finalmente, llegué a la conclusión, que desenredar el método es el camino a seguir. Utilizaré la terminología kafka de productores/consumidores/temas. Para más información ver The Log: What every software engineer should know about real-time data's unifying abstraction y en particular este gráfico:

enter image description here

En cuanto a mi pregunta específica del ejemplo publicado, hay dos formas de resolverlo:

Solución 1

  • Consumidor 1:
    • consumen para m tema a
    • guardar en la base de datos.
  • Consumidor 2:
    • consumir de tema a
    • cálculo b
    • guardar en la base de datos.
  • Consumidor 3: consumir de tema a
    • cálculo b
    • cálculo c
    • guardar en la base de datos

Esto tiene la desventaja de calcular bdos veces. En pseudo-código:

class ConsumerA { 
    public void consume(A a) { 
     saveObjectToDatabase(a); 
    } 
} 

class ConsumerB { 
    public void consume(A a) { 
     B b = computeB(a); 
     saveObjectToDatabase(b); 
    } 
} 

class ConsumerLog { 
    public void consume(A a) { 
     B b = computeB(a); 
     C c = computeC(b); 
     logToFile(c); 
    } 
} 

Solución 2

  • Consumidor 1:
    • consumir de tema a
    • guardar en la base de datos.
  • Consumidor 2:
    • consumir de tema a
    • b de cómputo, guardar en la base de datos
    • publicar b a un tema aparte b.
  • Consumidor 3:
    • consumir de tema b
    • cálculo c
    • LogToFile c

En pseudo-código:

class ConsumerA { 
    public void consume(A a) { 
     saveObjectToDatabase(a); 
    } 
} 

class ConsumerB { 
    public void consume(A a) { 
     B b = computeB(a); 
     saveObjectToDatabase(b); 
     publish(b); // republish computed information to another topic b 
    } 
} 

class ConsumerLog { 
    public void consume(B b) { 
     C c = computeC(b); 
     logToFile(c); 
    } 
}