Cómo mantener el orden después de la recopilación de procesamiento de subprocesos múltiples

antecedentes

En la llamada de interfaz por lotes, no elegiremos el método de llamada en serie de recorrido cíclico, porque el tiempo de respuesta será la suma de todos los tiempos de llamada, como verificar 100 datos, cada consulta es de 50 milisegundos y el tiempo total de llamada cíclica en serie. 100 * 50 = 5000 milisegundos.

Por lo general, elija utilizar la interfaz de consulta por lotes o multiproceso para resolver los problemas anteriores. Sin embargo, debido al paralelismo de multiproceso y afectado por las fluctuaciones de la red, los resultados se devolverán primero después de la ejecución. En algunos escenarios donde se requiere orden, es necesario prestar atención a si el orden de los resultados es consistente con el orden de las solicitudes.

Por ejemplo

Para diferentes escenarios comerciales, se dan dos ejemplos:

  1. Use List <Future <T>> para guardar el Future devuelto por la ejecución del grupo de subprocesos. Cuando se obtiene el resultado, dado que la lista está ordenada, también se ordena el resultado obtenido al recorrer Lista <Futuro <T>>. El siguiente ejemplo simple:

    ExecutorService executor=....;//线程池
    List<Integer> idList=...;//待查询的id
    List<someDto> resultList=new ArrayList();//存放查询的结果
    List<Future<someDto>> futureList=new ArrayList();//存放线程池查询的Future
    
    //此时,线程池是按idList的顺序遍历的,所以idList中顺序和futureList中顺序一致
    idList.forEach(id->{
    	futureList.add(executor.submit(()->{
    		return someService.queryById(id);
    }));
    });
    //此时是按照futureList的顺序遍历,所以resultList中的顺序和futureList顺序一致,也就和入参idList的顺序一致了
    futureList.forEach(future->{
    	resultList.add(future.get());
    });

     

  2. Use la programación de Stream, stream usa CompletableFuture para lograr un uso de múltiples subprocesos, un ejemplo simple es el siguiente:

    ExecutorService executor=....;//线程池
    List<Integer> idList=...;//待查询的id
    List<someDto> resultList=new ArrayList();//存放查询的结果
    List<someDto> sortedList=new ArrayList();//存放保序后的结果
    
    //这里从idList.stream()...开始看,allOf是从最后的结果集取值。
    //这里先遍历每个id,并执行someService.queryById获取结果,并使用thenAccept指定得到结果后,将结果放入resultList中。
    //使用map将CompletableFuture.supplyAsync的返回结果集转为数组(toArray()),CompletableFuture.allOf的入参是数组类型。
    //最终使用get()获取所有的值,此时由于多线程响应的快慢不一样,所以顺序已经乱了。
    CompletableFuture.allOf(idList.stream()
    			.map(id -> CompletableFuture.supplyAsync(() -> someService.queryById(id), executorService).thenAccept(resultList::add))
    			.toArray(CompletableFuture[]::new))
    			.get();
    //这里将乱序的结果resultList,转换成Map,其中key是id,value是每个子项自己。
    Map<Integer,someDto>map=resultList.stream().collect(Collector.toMap(someDto::getId,dto->dto));
    //遍历入参idList,按照id从上述map中逐个get值,以达到保序的功能
    idList.forEach(id->{
    	sortedList.add(map.get(id));
    });

     

Comparar

Independientemente del rendimiento, en general, el uso de múltiples subprocesos de la transmisión parece ser más complicado que el uso tradicional de Future. Pero si el escenario empresarial no es un simple uso de múltiples subprocesos, el uso convencional no puede resolver el problema. Tome el primer ejemplo como ejemplo:

ExecutorService executor=....;//线程池
List<Integer> idList=...;//待查询的id
							......
//*************注意这里*************
//此处添加一个批量操作,先对idList做一次封装,封装后再用封装的结果执行多线程,如果这里调用的批量服务不能保序,如搜索,数仓等接口,用其默认的排序。
List<midDto> midList=midService.batchWrap(idList);
//再对midList做多线程操作,此时,多线程futureList中的顺序和批量操作返回的顺序相同,不再和idList一致
							......

En este punto, es necesario realizar un proceso de conservación del conjunto de resultados.

¿Tienes otras ideas? Bienvenido a dejar un mensaje para compartir ~

Supongo que te gusta

Origin blog.csdn.net/u013821237/article/details/104449735
Recomendado
Clasificación