Tenedor-Únete Desarrollo en Java ™ SE

Original article you can find here http://coopsoft.com/ar/ForkJoinArticle.html

Tenedor-¡Únete cotidianas, aplicaciones multi-core de Java ™

Bifurcar o dividir la carga de trabajo en múltiples tareas para el procesamiento paralelo y uniendo los resultados juntos es una técnica utilizada en cálculos numéricos innumerables aplicaciones científicas,. Muchas otras aplicaciones podrían beneficiarse de procesamiento tenedor-join pero utilizando el enfoque científico pueden no estar en su mejor interés.

Este artículo presenta una "vergonzosamente paralelas" tenedor-join enfoque que funciona bien para aplicaciones de todos los días, con múltiples núcleos en Java ™ SE, ME, así como Android. ™ (3000 palabras)

¿Qué se Tenedor-Unirse?

Piense en un tenedor en la carretera, donde cada camino finalmente regresa juntos - uniones.

Tenedor-Únete rompe una aplicación en varias partes para el procesamiento en paralelo y se une a los resultados al final.

Figura 1: Estructura Tenedor-Únete

Fork-Join Structure

Digamos que tenemos una gran variedad de mil números. Tenemos que hacer un procedimiento en cada uno de estos números y agregar el total.

Ficha 1: Procesamiento de matriz

 
 
for (int i = 0; i < 1000; i++) {
      total += doProcedure(array[i]);
  }

Si el procedimiento dura un segundo (tiempo del reloj de pared) para completar, entonces se va a tomar un mil segundos (más de 16½ minutos) para completar esta tarea.

Tenedor-Únete podía

  • aparte (tenedor) la gran variedad en diez series de cien elementos cada uno
  • procesa cada matriz en una CPU separada, y
  • unirse a los resultados cuando haya terminado

Eso llevaría cien segundos (poco más de 1 ½ minutos), una décima parte del tiempo original. Disponible, más rápidamente el resultado Cuanto más de CPU.

Esto es lo que la computación científica es todo - el procesamiento simultáneamente cantidades gigantescos de datos sobre como de muchas CPU como disponible. Esta abstracción se asemeja mucho al modelo científico estándar de Divide y vencerás..

Divide y vencerás es un paradigma natural para algoritmos paralelos. Después de dividir un problema en dos o más sub-problemas, el método resuelve los sub-problemas en paralelo. Típicamente, los sub-problemas se resuelven de forma recursiva y por lo tanto el siguiente paso brecha rinde aún más sub-problemas para resolver en paralelo.

Figura 2: Divide y vencerás

Divide and Conquer

Problemas al utilizar Tenedor-Únete modelo científico para las aplicaciones diariass

Creación de tareas no es el problema; son sólo objetos. El problema es un alto número de hilos de procesamiento de las tareas cuando las tareas necesitan:

Conexiones
Acceso a servicios remotos (DBMS, mensajería, y muchos otros) requiere una conexión con el servicio remoto. En general, los servicios remotos utilizan un subproceso para controlar la conexión y que requiere la memoria, el cambio de contexto, la sincronización y coordinación. Cuantas más conexiones al servicio, más recursos al servicio de las necesidades y las menos conexiones disponibles para otras tareas en la JVM. Eso afecta a todos los usuarios.

Cabellos
Locks son un asesino de alto rendimiento. Cerraduras muertos / vivos, inversión de prioridad, de hambre, convoyar y generales (que sube exponencialmente con la longitud de la lista de tareas en espera) son algunos de los problemas del uso de bloqueos.

Semáforos
Los más hilos que quieren un permiso simultáneamente, más hilos que deben esperar disponibilidad permiso. Esto nos lleva de nuevo a todos los problemas del uso de bloqueos.

Coherencia de caché
Cuando varios procesadores de acceso / actualizar la misma variable dentro de una línea de caché, (bloque de datos copiados de la memoria principal contiene muchos campos), la unidad de memoria puede invalidar la línea de caché. Eso no sólo ralentiza una aplicación, ésta puede afectar a otras aplicaciones también.

Amplia memoria
Cuantos más objetos o los más grandes los objetos, más memoria. Los hilos más activos de manejo de las tareas, entonces el más memoria en uso. Naturalmente, se deduce que las tareas de memoria grandes necesitan de estrangulamiento.

La necesidad de jugar bonito
Usted es de aplicación puede no ser la única aplicación que se ejecuta en el equipo. Cuando una aplicación acapara los recursos, todo el mundo siente el dolor. Jugar bien con los demás se remonta a lo que todos aprendimos en la infancia. Lo mismo ocurre cuando el desarrollo de software que no se ejecuta como una aplicación independiente.

El tema del desarrollo multi-núcleo es mantener a contención, tareas que compiten por los mismos recursos, a un mínimo.

Si el paradigma descomposición dinámica de Divide y vencerás se adapte a sus necesidades, entonces lee este artículo sobre el alto rendimiento versión DSE de Tymeac . De lo contrario un marco funcional puede bifurcar mejor se adapte a sus necesidades.

Marco Forking Funcional

Java ™ SE / ME aplicaciones multi-core, así como Android ™ aplicaciones que no pueden utilizar el modelo Divide y vencerás, no procesar grandes conjuntos de números, o que no tienen una estructura de cómputo intensivo necesita un marco bifurcación funcional para aplicaciones paralelización . En concreto, tienen que desembolsar el trabajo en sus componentes funcionales en lugar de descomponer una matriz en subtareas idénticos.

Figure 3: Functional Forking Framework

Functional Forking Framework

Un marco bifurcación funcional tiene dos atributos esenciales. Se debe:

  • Limite la contención.
  • BSer fácil de usar o embarazosamente paralelo.

Límite de Contención

Mantener el número de competidores, hilos activos a un mínimo absoluto es primordial. La forma más fácil para limitar la contención del hilo es utilizar umbrales para cada grupo de subprocesos servicio a una cola de tareas. Ver este artículo en colas de prioridad de Alto Rendimiento en Java SE para un ejemplo de cómo el uso de las listas de espera pueden conservar los recursos de roscado.

La reutilización de los recursos en lugar de adquirir nuevas copias de los recursos es un ganador todo alrededor. Tenemos que tener en cuenta no sólo el código de tarea, pero el código de gestión de recursos también.

Tomemos el ejemplo de una tarea necesidad de acceder a una base de datos que requiere una declaración [java.sql.]. Mediante el uso de una cola de solicitudes, el código de tarea puede compartir la misma declaración para muchos accesos en lugar de la adquisición de una nueva declaración para cada acceso. Compartir una declaración es un gran ahorro en la pelea de arriba y los límites en el código de gestión.

¿Qué es paralela vergonzosamente?

Vergonzosamente algoritmos paralelos son los que pueden resolver muchas tareas similares, pero independientes de manera simultánea con poca o ninguna necesidad de coordinación entre las tareas. Este tipo de problemas tienen como paralelización fácil que uno es casi "vergüenza" para hablar de lo fácil que es conseguir muchos procesadores que trabajan de manera eficiente.

Una solución embarazosamente paralelo puede bifurcar fácilmente en un número de componentes completamente independientes, cada uno se ejecuta en un procesador separado.

Figure 4: Embarrassingly Parallel

Embarrassingly Parallel

Por ejemplo:
Una empresa puede necesitar un sistema de cotización automatizada. Para desarrollar un presupuesto, el sistema necesita el precio del artículo base (base de datos de precios), con descuento del cliente para los artículos y envío (base de datos de clientes), y los gastos de envío básicos (base de datos cargador.)

Tradicionalmente, el programa accede a cada base de datos en serie, a la espera de una visita a completar antes de pasar a la siguiente acceso.

En un sistema paralelo, las bifurcaciones de programa () la petición en tres colas, cada una atendida por un grupo de subprocesos, espera hasta el último acabados de acceso y se une () los resultados juntos.

Figure 5: Price Quote

La cotización del precio anterior es un ejemplo de una petición síncrona, donde el llamante espera para su conclusión. Es sólo un pequeño paso adelante para añadir soporte para la solicitud asincrónica o autónoma, donde la persona que llama no espera a la finalización.

Hay muchas, muchas situaciones en las que es deseable que se bifurcan los trabajos en sus componentes:

  • Tome una aplicación de juego en el que podemos desembolsar un evento en componentes separados. La ventaja aquí es la emoción; los más segmentos de los eventos que tienen lugar al mismo tiempo, el más interesante el juego.
  • Tome una aplicación con múltiples animaciones donde podemos fork cada animación para ejecutarse en su propio procesador.
  • Tome una operación de procesamiento de imagen, donde cada píxel en una imagen necesita tener su color inverso. El marco puede distribuir fácilmente los datos de imagen a múltiples tareas que pueden trabajar independientemente uno de otro.
  • Tome una institución financiera donde re-valoración de una cartera incluye componentes que se comunican con varios mercados alrededor del mundo.
  • Tome una aplicación de asistencia sanitaria en diferentes pruebas son componentes de un diagnóstico.

Es un esfuerzo para ver lo que la aplicación no puede utilizar la paralelización con un marco bifurcación funcional.

¿Cómo sería este marco mirar en una aplicación Java ™?

Un marco para bifurcar la solicitud en sus componentes funcionales tiene que:

Conocer los componentes (colas) para cada operación de petición (Función). Una clase simple que contiene un nombre de función de cadena y una lista de las colas asociado es ™ programación básica Java.

Ficha 2: Función Clase

 
 
public class Function {

      private String    name; // Function name
      private Queue[] que;   // Queues for this Function
  }
 

Coloque la solicitud (que contiene los objetos de entrada) en cada una de las colas que regresan una tabla de objeto a la persona que llama o haciendo caso omiso de los objetos devueltos.

Ficha 3: Poner en cola

 
 
public Object[] fork(Queue[] que, Object request) {

      Object[] return_obj = new Object[] {null, null, null};

      for (int i = 0; i < que.length; i++) {
           putInQueue(que[i], return_obj [i], request);
      }

       return return_obj;
}
 

Esperar a la finalización / tiempo de espera o no espere.

Listado 4: Espera / nowait

 
 
public boolean join(Object[] obj) {

    /* when all elements are non-null, return true
     * wait for a while
     * after an interval, return false
     */

  }
 

Devolver los resultados a la persona que llama o ignorar los objetos

Figura 6: Retorno al llamante

Return Object[]

 

 

 

 

 

Para construir este marco lo haríamos:

  1. Necesidad de mantener el código tarea real que hace el trabajo
  2. Necesidad de mantener una lista de las colas y Funciones
  3. Necesidad de mantener una clase de "puesta en marcha" que carga las colas y funciones en la memoria

(1) El código que hace el trabajo debería tener este aspecto:

Listado 5: Código de Trabajo

 
 
public static Object main(Object obj) {}
 

Un método main () que acepte un objeto (la entrada de la persona que llama) y devuelve un objeto (el resultado de la obra.)

(2) Podríamos mantener las colas y funciones como objetos dentro de una lista simple clase.

(3) Poner en marcha podría simplemente cargar las clases de lista en la memoria con un nuevo (Lista de clase) y comenzar las discusiones para cada cola.

¿Cómo una simple llamada podía mirar:

Ficha 6: Call simple

 
    Framework
fw = new Framework();

    // For each call:
    Function
func = fw.getFunction(name);
    Object[] back =
func.fork(request};
 

Este marco es simple de usar, vergonzosamente simple.

Resumen

Hasta ahora, hemos visto cómo se bifurcan una solicitud en sus componentes funcionales pueden funcionar como una parte incorporada de una sola aplicación (dentro de la misma JVM). Para ser prácticos, también tenemos que hacer que el marco accesible desde otra JVM. Simplemente, tiene que soportar muchas llamadas de los usuarios al mismo tiempo como un servidor.

Por lo que es un servidor

¿Qué cambios debemos hacer para forjar este simple marco en un servidor?

  1. Debemos separar la persona que llama desde el trabajo.
  2. Debemos proporcionar la recuperación de errores.
  3. Debemos apoyar el marco como un objeto remoto.
  4. Debemos proporcionar seguridad.
  5. Debemos proporcionar funcionalidad administrativa para controlar el servidor.


Separación
El primer cambio es separar la intermediación de solicitud (que es el método tenedor arriba ()) de la transformación real. Tenemos que separar, pero no perder de vista, cada petición en un objeto único.

Listing 7: Request Object

 
  private long              unique_id; // unique identification of this request
  private Object           input; // input reference, if any
  private boolean         type; // type of request true=sync false=async
  private Object[]         output // the output objects from the tasks
  private AtomicInteger next_output; // subscript to add an element to above
  private Queue[]         que_names; // list of all the queues in this function
  private Queue            agent; // future queue, if used
  private AtomicInteger nbr_remaining; // queues remaining to be processed
  private int                wait_time; // max wait time for sync request
 

¿Cuál es el campo "agente?"

Agente
A petición síncrona devuelve la matriz de objeto de la transformación de la persona que llama. ¿Qué debe hacer el marco con la matriz de objetos de regresar de una solicitud asincrónica? El marco puede, opcionalmente, poner la matriz de objeto (como una entrada) en una nueva cola para su procesamiento por una tarea de agente. De esta manera la tarea de agente puede tomar medidas basadas en el estado de finalización del procesamiento previo.

Por ejemplo:
Una función es generar un presupuesto y enviarlo por correo electrónico a un usuario como una solicitud asincrónica.

  1. La persona que llama utiliza el método tenedor asíncrono ().
  2. Las horquillas marco de la solicitud en sus respectivas colas.
  3. Cuando el último de la cola termina, el marco pasa la matriz objeto devuelto a la tarea de agente poniendo la solicitud a la cola especificada como "agente".
  4. La tarea de agente envía el email regresar nada.

La recuperación de errores
El segundo cambio es la adición de la recuperación de errores, la marca de profesionalismo.

¿Qué puede salir mal aquí? "Todo lo que puede salir mal, saldrá mal." La ley de Murphy ..

Back out
We could have a forking error. A bounded Queue could be full or the Queue could be disabled (more on this below.) Error recovery should back out all the Queues that forked successfully and inform the caller of the problem. For example:

We have three Queues (A, B, C) in the Function.
Queues A and B successfully receive the request.
Queue C fails to receive the request because the Queue is full.
Now we go backwards trying to pull the request out of all the Queues that forked successfully so we can save processing time for faulty requests.

Exception/Error
We could have an exception/error in the actual task code that does the work. If it failed once, it probably will fail again. Therefore, it is advisable to disable the Queue until a developer fixes the problem. When the task code is clean, we don’t want to take down the server. We want to inform the server that we have a new copy of the task code that is clean and we want the Queue enabled.

Stall
We could have the above happen in an asynchronous request, called a stall (synchronous requests time out and can purge from the system.) Since Functions cannot complete until all the Queues finish, we need to place stalled requests into a Stalled List. When the Queue is again serviceable, we can re-start the processing from the Stalled List.

.
Compactar es un tema en sí mismo y requiere contención hilo. En este artículo se presenta el tema: Gestión de Hilos en Java SE

Dilema Tema
Podríamos tener una secuencia de rosca para siempre en un recurso externo o entrar en un bucle sin fin. De cualquier manera, midiendo el tiempo de acontecimientos en la vida de un hilo, el marco puede reconocer esta situación y puede borrar el hilo sustitución por un nuevo hilo.

Cancelado
Podríamos tener una persona que llama quiere cancelar una solicitud presentada anteriormente. La cancelación es similar a un error de tiempo de espera, pero es aplicable a ambas peticiones síncronas y asíncronas. Aunque la cancelación de una solicitud es la más deseable, la lógica para el manejo de una cancelación de un pedido de varios componentes no es para los débiles de corazón.

Monitoreo
El tiempo es inútil a menos que un hilo de utilidad monitorea los eventos programados en busca de problemas reales o potenciales.

Notificación
Sin marco puede manejar todas las situaciones; a veces es necesario la intervención humana. Debemos notificar a los administradores mediante el envío de un mensaje a través de cualquier medio los usos organización (mensajería instantánea, correo electrónico o cualquier método de cosecha propia.)
Objeto remoto

El tercer cambio está apoyando el marco como un objeto remoto con la opción de activación / desactivación para conservar los recursos.

Invocación a método remoto viene en muchos sabores:
Básico
Custom fábrica Socket
IIOP
Adaptador Portable Object
Jini
Inter Process Communication

El entorno puede consistir en una nube con procesadores separados en muchos lugares diferentes. Haciendo el marco flexible tiene mucho sentido.

Seguridad
El cuarto cambio es la adición de la seguridad.

La tecnología de seguridad de Java ™ es ​​parte de la SE / ME plataformas, requiere adelantado terminando el servidor con clases de seguridad para una mayor flexibilidad.

Las funciones del administrador
El quinto cambio es la adición de funciones de administrador.

El registro es aburrido y sobre todo inútil, hasta que algo sale mal.

Las estadísticas son la base para el análisis de rendimiento y el ajuste.

Tenemos que proporcionar interfaces a las estructuras internas para que los usuarios pueden monitorear y controlar la funcionalidad. No sirve de mucho si no se sabe lo que está haciendo. Una vez que la gente sepa lo que está haciendo, es probable que desee cambiarlo.

Escribir un marco Tenedor-Únete a que es fácil de usar y eficiente para llamadas locales es difícil. Hacer lo mismo para el acceso a la red es una empresa importante.

¿Cuánto tiempo se tarda en construir tal un servidor?
Cerca de 5-6 segundos. Lo suficiente para descomprimir un archivo.
Felizmente, hay de propósito general, tenedor-join marcos de apoyo a las propiedades mencionadas anteriormente para aplicaciones de todos los días, con múltiples núcleos en Java ™ SE, ME y Android ™ disponibles en la actualidad. Y puesto que el marco puede ejecutarse como un servidor RMI (estándar / activable, IIOP y POA) que está disponible para aplicaciones Java EE ™.

Tymeac ™ para Java ™ SE / ME / plataformas Android ™ están abiertos proyectos de software de código mantenidos en
y se puede descargar las últimas ediciones allí.
Conclusión

Usando un Únete Tenedor marco desarrollado por las comunidades de cálculo intensivo podría no funcionar bien para las aplicaciones diarias.

La mayor parte de las aplicaciones Java ™ multi-core tiene que desembolsar el trabajo en sus componentes funcionales con un marco de calidad profesional que es fácil de usar, eficiente y de código abierto.

Referencias
Descargas:
Descargue la última edición SE de Tymeac aquí . Con toda la documentación, scripts, clases y fuente.

Descargue la última edición de ME Tymeac aquí . Con toda la documentación y la fuente.

Descargue la última edición de Y Tymeac aquí . Con toda la documentación y los proyectos de Eclipse completos.

Descargue la última edición DSE de Tymeac aquí . La versión Divide y vencerás.

Artículos:

El alto rendimiento versión Divide y vencerás de Tymeac - Un Tenedor Java-Únete Conquistador

La versión de Android ™ de alto rendimiento de Tymeac - Gestión de Temas en Android

El uso de las listas de espera para la Eficiencia - colas de prioridad de Alto Rendimiento en Java SE

El Hilo de contenedores Java ™ SE - Gestión Hilos en Java SE

Otros:
Tenedor-join wiki cola - http://en.wikipedia.org/wiki/Fork-join_queue
Ley de Murphy - http://en.wikipedia.org/wiki/Murphy%27s_law
CPU caché wiki - http://en.wikipedia.org/wiki/CPU_cache
Caché coherencia wiki - http://en.wikipedia.org/wiki/Cache_coherence
Wiki embarazosamente paralelo - http://en.wikipedia.org/wiki/Embarrassingly_parallel

Sobre el Autor

Edward Harnedes un desarrollador de software con experiencia más de treinta años la industria. La primera vez que dirigió proyectos como empleado en las principales industrias y luego trabajó como consultor independiente. Hoy, Ed es un desarrollador senior de Cooperative Software Systems, Inc., donde, durante los últimos doce años, ha utilizado programación Java ™ para dar tenedor-join soluciones a una amplia gama de tareas.

Copyright 2015 | A special thanks for the financial support with this project to website