Comparta una herramienta de tareas asincrónicas por lotes JDK CompletionService, súper fácil de usar

Resumen: se recomienda CompletionService cuando necesita enviar tareas asincrónicas en lotes. CompletionService integra el ejecutor del grupo de subprocesos y la cola de bloqueo para facilitar la gestión de tareas asincrónicas por lotes.

Este artículo es compartido por la comunidad HUAWEI CLOUD " CompletionService, la herramienta más sólida para tareas asincrónicas por lotes de JDK ", autor: JavaEdge.

¿Cómo optimizar un código que consulta varias interfaces de precios? Si se utiliza "ThreadPoolExecutor+Future", se puede optimizar de la siguiente manera:

Los tres subprocesos ejecutan el precio de la consulta de forma asíncrona, obtienen el resultado llamando al método get() de Future tres veces y luego guardan el resultado de la consulta en MySQL.

Si obtener precio1 toma mucho tiempo, incluso si obtener precio2 toma poco tiempo, la operación de guardar precio2 no se puede ejecutar primero, porque el hilo principal está bloqueado en f1.get(). ¿Cómo resolver este problema?

¡Agregue una cola de bloqueo! Los precios obtenidos 1, 2 y 3 ingresan a la cola de bloqueo y luego consumen la cola de bloqueo en el subproceso principal para garantizar que el precio obtenido primero se guarde primero:

CompletionService implementa el precio de la consulta

El desarrollo real recomienda CompletionService, que no solo puede ayudarlo a resolver el precio obtenido primero y guardarlo primero, sino que también simplifica el código.

CompletionService mantiene una cola de bloqueo internamente. Cuando finaliza la ejecución de la tarea, el resultado de la ejecución de la tarea se pone en cola. Sin embargo, CompletionService pone en cola el objeto Future del resultado de la ejecución de la tarea, y la demostración anterior pone en cola el resultado final de la ejecución de la tarea.

Crear servicio de finalización

La clase de implementación de la interfaz CompletionService es ExecutorCompletionService.Existen dos métodos de construcción para esta clase de implementación, a saber:

  • ExecutorCompletionService (ejecutor ejecutor);

  • ExecutorCompletionService(Ejecutor ejecutor, BlockingQueue<Future<V>> cola de finalización)

Ambos constructores deben pasar un grupo de subprocesos. Si no se especifica la cola de terminación, se usa la cola de bloqueo ilimitada sin límites de forma predeterminada. El objeto futuro del resultado de la ejecución de la tarea se agrega a la cola de finalización.

Senior~ Puedes escribir un código para explicármelo directamente~

Intentemos usar CompletionService para implementar un sistema de precios de consulta de alto rendimiento. Después de eso, envíe tres operaciones de consulta a través de CompletionService#submit(), y CompletionService ejecutará estas tres operaciones de consulta de forma asíncrona.

Finalmente, CompletionService#take() obtiene un objeto Future (el objeto Future del resultado de la ejecución de la tarea agregado a la cola de bloqueo), y llamar a Future#get() puede devolver el resultado de la ejecución.

Interfaz de servicio de finalización

Métodos proporcionados por la interfaz CompletionService

Hay dos métodos relacionados con el envío():

  • Un parámetro de método es la tarea Callable<V>
  • Un método tiene dos parámetros, a saber, Runnable task y V result, este método es similar a ThreadPoolExecutor's <T> Future<T> submit(Runnable task, T result) ,

CompletionService implementa Dubbo#Forking Cluster

Hay un modo de clúster llamado bifurcación en Dubbo. En este modo de clúster, se pueden llamar varios servicios de consulta en paralelo. Siempre que uno devuelva el resultado con éxito, se puede devolver el servicio completo. Por ejemplo, debe proporcionar un servicio de dirección a coordenadas Para garantizar la alta disponibilidad y el rendimiento del servicio, puede llamar a las API de tres proveedores de servicios de mapas en paralelo, y siempre que uno de ellos devuelva el resultado r correctamente, el servicio de dirección a coordenadas será Puede volver directamente a r. Este modo de clúster puede tolerar la excepción de dos proveedores de servicios de mapas, pero la desventaja es que consume demasiados recursos.

 geocoder(addr) {
   // 并行执行以下3个查询服务, 
   r1=geocoderByS1(addr);
   r2=geocoderByS2(addr);
   r3=geocoderByS3(addr);
   // 只要r1,r2,r3有一个返回
   // 则返回
   return r1|r2|r3;
 }

El modo de clúster de bifurcación se puede implementar rápidamente mediante CompletionService, como el siguiente código de ejemplo. Primero cree un ejecutor de grupo de subprocesos, un objeto CompletionService cs y una lista de futuros de tipo Future<Integer>, cada vez que se envíe una tarea asíncrona llamando al método submit() de CompletionService, se devolverá un objeto Future y estos objetos Future se guardará en la lista en futuros. Al llamar a cs.take().get(), podemos obtener el resultado de ejecución de tareas devuelto más rápido. Siempre que obtengamos un resultado devuelto correctamente, podemos cancelar todas las tareas y devolver el resultado final.

 // 创建线程池
 ExecutorService executor =
   Executors.newFixedThreadPool(3);
 // 创建CompletionService
 CompletionService<Integer> cs =
   new ExecutorCompletionService<>(executor);
 // 用于保存Future对象
 List<Future<Integer>> futures =
   new ArrayList<>(3);
 // 提交异步任务,并保存future到futures 
 futures.add(
   cs.submit(()->geocoderByS1()));
 futures.add(
   cs.submit(()->geocoderByS2()));
 futures.add(
   cs.submit(()->geocoderByS3()));
 // 获取最快返回的任务执行结果
 Integer r = 0;
 try {
   // 只要有一个成功返回,则break
   for (int i = 0; i < 3; ++i) {
     r = cs.take().get();
     // 简单地通过判空来检查是否成功返回
     if (r != null) {
       break;
     }
   }
 } finally {
   // 取消所有任务
   for(Future<Integer> f : futures)
     f.cancel(true);
 }
 // 返回结果
 return r;

Resumir

Cuando necesite enviar tareas asincrónicas en lotes, se recomienda CompletionService. CompletionService integra el ejecutor del grupo de subprocesos y la cola de bloqueo para facilitar la gestión de tareas asincrónicas por lotes.

CompletionService puede hacer que los resultados de ejecución de tareas asincrónicas sean ordenados, y aquellos que se ejecutan primero ingresan primero a la cola de bloqueo. Con esta función, el orden del procesamiento posterior se puede lograr fácilmente, se pueden evitar esperas innecesarias y se pueden cumplir requisitos como Forking Cluster. ser rápidamente realizado. .

La clase de implementación de CompletionService, ExecutorCompletionService, requiere que usted mismo cree un grupo de subprocesos. Aunque parece un poco largo, la ventaja es que puede aislar los grupos de subprocesos de varios ExecutorCompletionServices. Este rendimiento de aislamiento evita varios que consumen mucho tiempo. tareas de arrastrar hacia abajo toda la aplicación.

 

Haga clic en Seguir para conocer las nuevas tecnologías de HUAWEI CLOUD por primera vez~

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4526289/blog/5520054
Recomendado
Clasificación