Cómo crear múltiples hilos para cada artículo de solicitud

9

Estoy tratando de procesar el siguiente código usando subprocesos múltiples en el nivel de pedido.

List<String> orders = Arrays.asList("order1", "order2", 
                   "order3", "order4", "order1");

Ejecución secuencial actual:

orders.stream().forEach(order -> {
    rules.forEach(rule -> {
        finalList.add(beanMapper.getBean(rule)
                .applyRule(createTemplate.apply(getMetaData.apply(rule), command),
                           order));
    });
});

He intentado usar:

orders.parallelStream().forEach(order -> {}} // code snippet.

Pero está cambiando las reglas . Para cada orden (regla -> {}} .

Por ejemplo:
Entrada:

 List<String> orders = Arrays.asList("order1", "order2", 
                         "order3", "order4", "order1");
 List<String> rules = Arrays.asList("rule1", "rule2", "rule3");

Rendimiento esperado:

order1 with rule1, rule2, rule3
order2 with rule1, rule2, rule3

Salida real con parallelStream():

order1 with rule3, rule1, rule2
order1 with rule2, rule1, rule3

No me preocupa el orden de las órdenes , pero me preocupa el orden de las reglas . Las órdenes pueden procesarse en cualquier orden, pero las reglas deben ejecutarse en el mismo orden para cada orden.

Por favor ayuda.

Mayank Bisht
fuente

Respuestas:

4

Puedes usar :

orders.stream().parallel().forEachOrdered(// Your rules logic goes here. )

ForEachOrdered garantiza mantener el orden del Stream.

Entonces para su referencia:

orders.stream().parallel().forEachOrdered( order -> {

            rules.stream().parallel().forEachOrdered ( rule -> {

                 System.out.println( " Order : " + order + " rule :" + rule);
            });

        });

Nota: Si bien podemos hacer esto, el rendimiento debe vigilarse de cerca porque el paralelismo y el orden no se casan muy bien.

Salida

 Order : order1 rule :rule1
 Order : order1 rule :rule2
 Order : order1 rule :rule3
 Order : order2 rule :rule1
 Order : order2 rule :rule2
 Order : order2 rule :rule3
 Order : order3 rule :rule1
 Order : order3 rule :rule2
 Order : order3 rule :rule3
 Order : order4 rule :rule1
 Order : order4 rule :rule2
 Order : order4 rule :rule3
 Order : order1 rule :rule1
 Order : order1 rule :rule2
 Order : order1 rule :rule3
Pramod S. Nikam
fuente
Gracias por la respuesta. forEachOrdered garantiza el orden de la transmisión, pero también ralentiza el rendimiento. Lo probé y la aplicación está tomando un tiempo similar al procesamiento secuencial. stream (). parallel & forEachOrdered no se complementan entre sí.
mayank bisht
Sí, estoy de acuerdo en que necesitamos hacer un análisis de latencia completo antes de hacer esto.
Pramod S. Nikam
Sí, obtengo el mismo rendimiento con esto, no hay mejora.
mayank bisht
1
Siga de cerca este hilo para obtener una mejor solución para hacer esto.
Pramod S. Nikam
¿Puedo lograr el procesamiento paralelo con ExecutorService?
mayank bisht
1

Agrega elementos a finalListdiferentes hilos al mismo tiempo. Esto está causando resultados mixtos al aplicar reglas a diferentes órdenes (las reglas no se agrupan por sus órdenes).

Puede solucionarlo creando una lista temporal para cada uno ordery luego fusionando sincrónicamente todas las listas temporales en a finalList.

Así es como puede hacerlo utilizando Stream-API (Java 9+):

List<AppliedRule> finalList = orders.parallelStream().map(order ->
        rules.stream().map(rule -> applyRule(order, rule)).collect(Collectors.toList())
).collect(Collectors.flatMapping(Collection::stream, Collectors.toList()));

Nota: Collectors.flatMapping()se usa aquí en lugar de una simple flatMapasignación plana sincrónica durante la recopilación de secuencias.


Java 8 analógico:

List<AppliedRule> finalList = orders.parallelStream().map(order ->
        rules.stream().map(rule -> applyRule(order, rule)).collect(Collectors.toList())
).collect(Collectors.toList())
        .stream()
        .flatMap(Collection::stream)
        .collect(Collectors.toList());
Bananon
fuente
Gracias por la respuesta. Intenté su enfoque y estoy obteniendo java.util.ConcurrentModificationException: null
mayank bisht
finalList = orders.parallelStream () .map (order -> rules.stream () .map (rule -> beanMapper.getBean (rule) .applyRule (createTemplate.apply (getMetaData.apply (rule), command), order)) .collect (Collectors.toList ())). collect (Collectors.toList ()). stream (). flatMap (Collection :: stream) .collect (Collectors.toList ());
mayank bisht
@mayankbisht, esto significa que beanMapper.getBean(rule) .applyRule(createTemplate.apply(getMetaData.apply(rule), command), order)no es una función pura, por lo que no se puede usar en paralelo. Intenta eliminar todos los efectos secundarios; ConcurrentModificationExceptionstack trace puede ayudar a localizarlos.
Bananon
0

esto funcionara?

final int rulesSize = rules.size();
AtomicInteger atomicInteger = new AtomicInteger(0);
orders.stream().parallel().forEach(order -> {
    IntStream.range(0, rulesSize).parallel().forEach( i -> {
        synchronized (atomicInteger) {
            System.out.println(" Order : " + order + " rule :" + rules.get(atomicInteger.getAndIncrement() % rulesSize));
        }
    });
});

Salida

 Order : order1 rule :rule1
 Order : order4 rule :rule2
 Order : order1 rule :rule3
 Order : order3 rule :rule1
 Order : order3 rule :rule2
 Order : order3 rule :rule3
 Order : order2 rule :rule1
 Order : order2 rule :rule2
 Order : order2 rule :rule3
 Order : order1 rule :rule1
 Order : order1 rule :rule2
 Order : order4 rule :rule3
 Order : order1 rule :rule1
 Order : order4 rule :rule2
 Order : order1 rule :rule3
BHAWANI SINGH
fuente
0

El orden de las órdenes puede ser cualquier cosa, pero el orden de las reglas no debe cambiar. También para una regla de orden particular debe venir en un grupo.

Si ese es el caso, no hay espacio para el paralelismo real.

Cuando

order1-rule1
order1-rule2
order2-rule1
order2-rule2

y

order2-rule1
order2-rule2
order1-rule1
order1-rule2

son las únicas ejecuciones válidas para 2 pedidos y 2 reglas,
y

order1-rule1
order2-rule1
order1-rule2
order2-rule2

se considera inválido, eso no es paralelismo, solo aleatorización de orders, presumiblemente sin ganancia. Si está "aburrido" de order1venir primero todo el tiempo, puede barajar la lista, pero eso es todo:

public static void main (String[] args) throws java.lang.Exception
{
    List<String> orders = Arrays.asList("order1", "order2", "order3", "order4");
    List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
    Collections.shuffle(orders);
    orders.forEach(order->{
        rules.forEach(rule->{
            System.out.println(order+"-"+rule);
        });
    });
}

Ni siquiera es necesaria la transmisión, solo dos bucles anidados. Prueba: https://ideone.com/qI3dqd

order2-rule1
order2-rule2
order2-rule3
order4-rule1
order4-rule2
order4-rule3
order1-rule1
order1-rule2
order1-rule3
order3-rule1
order3-rule2
order3-rule3


Respuesta original

Pero está cambiando las reglas. Para cada orden (regla -> {}}.

No, no lo hace. La orders puede superponerse, pero rulese mantiene el orden de s para cada orden. ¿Por qué un no paralelo forEachharía algo más?

Código de ejemplo:

public static void main (String[] args) throws java.lang.Exception
{
    List<String> orders = Arrays.asList("order1", "order2", "order3", "order4");
    List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
    orders.stream().parallel().forEach(order->{
        rules.forEach(rule->{
            System.out.println(order+"-"+rule);
        });
    });
}

Prueba: https://ideone.com/95Cybg
Ejemplo de salida:

order2-rule1
order2-rule2
order2-rule3
order1-rule1
order1-rule2
order1-rule3
order4-rule1
order4-rule2
order4-rule3
order3-rule1
order3-rule2
order3-rule3

El orden de orders es mixto, pero los rules siempre son 1-2-3. Creo que su salida simplemente ocultó los emparejamientos (en realidad no mostró cómo se generó).

Por supuesto, puede extenderse con algunos retrasos, por lo que el procesamiento de orders realmente se superpondrá:

public static void delay(){
    try{
        Thread.sleep(ThreadLocalRandom.current().nextInt(100,300));
    }catch(Exception ex){}
}

public static void main (String[] args) throws java.lang.Exception
{
    List<String> orders = Arrays.asList("order1", "order2", "order3", "order4");
    List<String> rules = Arrays.asList("rule1", "rule2", "rule3");
    orders.stream().parallel().forEach(order->{
        rules.forEach(rule->{
            delay();
            System.out.println(order+"-"+rule);
        });
    });
}

Prueba: https://ideone.com/cSFaqS
Ejemplo de salida:

order3-rule1
order2-rule1
order2-rule2
order3-rule2
order3-rule3
order2-rule3
order1-rule1
order4-rule1
order1-rule2
order4-rule2
order4-rule3
order1-rule3

Esto puede ser algo que has visto, solo que sin la orderxparte. Con los orders visibles, se puede rastrear que rulesiguen llegando como 1-2-3, pororder . Además, su lista de ejemplo contenía order1dos veces, lo que seguro no ayudó a ver lo que estaba sucediendo.

Tevemadar
fuente
Gracias por la respuesta. La salida anterior puede ser correcta para un menor número de pedidos. Pero si aumenta los pedidos, obtendrá un resultado diferente. Por ejemplo (order4-rule1 order4-rule2 order4-rule1) (order1-rule1 order1-rule2) (order3-rule1 order3-rule2) (order4-rule1 order4-rule2 order4-rule1 order4-rule2).
mayank bisht
El orden de las órdenes puede ser cualquier cosa, pero el orden de las reglas no debe cambiar. También para una regla de orden particular debe venir en un grupo. Por ej. (order1- rule 1 order1-rule2 order1-rule3) y no (order1-rule1 order2-rule1 order1-rule2 order1-rule3).
mayank bisht
@mayankbisht Creo que estas restricciones simplemente no permiten el procesamiento en paralelo. Ver respuesta actualizada (escribí la nueva parte al principio).
tevemadar
Sí, entiendo eso, y es por eso que publiqué esta pregunta aquí. Pensé que tal vez habría otra forma de hacerlo, o tal vez podríamos cambiar el algo
Mayank bisht
@mayankbisht podría describir por qué los orders no pueden superponerse (¿son rules afirmativos tal vez y existen en un número limitado de copias, tal vez solo una?). Pero, en general, no hay paralelismo sin que las cosas funcionen en paralelo, ese es el punto central del paralelismo después de todo.
tevemadar
0

Si no te importa probar la biblioteca de terceros. Aquí hay una muestra con mi biblioteca: abacus-util

StreamEx.of(orders).parallelStream().forEach(order -> {}}

E incluso puede especificar el número de hilo:

StreamEx.of(orders).parallelStream(maxThreadNum).forEach(order -> {}}

El orden de rulese mantendrá.

Por cierto, dado que está en flujo paralelo, el fragmento de código ...finalList.add(...probablemente no funcionará. Creo que es mejor recopilar el resultado para enumerarlo:

StreamEx.of(orders).parallelStream().map/flatMap(order -> {...}}.toList()

también es factible incluso si desea mantener el orden orderpor algún motivo más adelante:

StreamEx.of(orders).indexed().parallelStream()
      .map/flatMap(order -> {...}}.sortedBy(...index).toList()
user_3380739
fuente