2011-06-04 7 views
8

Este es el problema que tengo: tengo una gran secuencia de algunos objetos (List<SomeClass>), y quiero realizar alguna operación en todos los elementos de la lista y obtener una nueva secuencia (List<SomeOtherClass>).¿Cómo puedo paralelizar el mapeo de una lista?

igual:

List<SomeOtherClass> list = new ArrayList<SomeOtherClass>(); 
for(SomeClass sc : originalList) 
    list.add(someOperation(sc)); 

Desde operación someOperation no tiene ningún efecto secundario, y la lista es bastante grande, quiero que esta operación de mapeo se realicen en paralelo.

¿Cuál será la mejor manera de hacerlo en Java?

Respuesta

-2

Si está seguro de que no hay efectos secundarios, simplemente use el enhebrado. Por supuesto, puede usar el enhebrado cuando hay un efecto secundario. Pero en ese caso necesitará usar algunos mecanismos de bloqueo y sincronización.

Una muestra muy simple hilo del excelente libro de Bruce Eckel, Pensando en Java:

public class SimpleThread extends Thread { 
    private int countDown = 5; 
    private static int threadCount = 0; 
    public SimpleThread() { 
    super("" + ++threadCount); // Store the thread name 
    start(); 
    } 
    public String toString() { 
    return "#" + getName() + ": " + countDown; 
    } 
    public void run() { 
    while(true) { 
     System.out.println(this); 
     if(--countDown == 0) return; 
    } 
    } 
    public static void main(String[] args) { 
    for(int i = 0; i < 5; i++) 
     new SimpleThread(); 
    } 
} ///:~ 
+0

Primero lea la pregunta y la respuesta en sí. El énfasis de la pregunta es que no hay necesidad de preocuparse por la concurrencia. Y, por cierto, la muestra se llama SimpleThread. Simplemente muestra la ejecución simultánea de algún código en ejecución. Acerca de Java efectivo, admito ese libro y lo prefiero a Pensar en Java. Pero es más avanzado y decidí elegir una muestra simple de un libro que sea más adecuada para principiantes. Porque la pregunta parece ser una pregunta para principiantes. –

+0

Creo que en el caso del OP, esto solo intentará crear demasiados hilos y bloquear el programa. Recuerde: 'list' es ** grande **. – trutheality

+0

Por supuesto. La muestra es solo para introducir el concepto de subprocesamiento, no como código final para la pregunta.Para una gran cantidad de subprocesos, se debe usar una solución de agrupamiento de subprocesos. –

4

Una posible aplicación puede utilizar el marco Executor (ejemplo incluido).

+0

Si va a presentar simultaneidad, le recomiendo usar el marco Executor. Toma bastantes de los dolores de cabeza de distancia. –

1

Use el enhebrado y la partición de su trabajo utilizando sublistas.

1

Dividir la lista de entrada, y el uso de tareas FutureTask, y luego fusionar los resultados

0

Así es como normalmente lo hago:

// Somewhere define a static final int NUM_THREADS that is appropriate. 

ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS); 
// There are other options: look at what the Executors class has to offer. 

List<SomeOtherClass> list = new ArrayList<SomeOtherClass>(); 

List<Future<SomeOtherClass>> list = new ArrayList<Future<SomeOtherClass>>(); 

for(SomeClass sc : originalList) 
    futures.add(submit(new someOperation(sc))); 

for(Future<SomeOtherClass> future : futures) 
    list.add(future.get()); // Again, see the docs, you can also set a timeout. 

exec.shutdown(); // Important. Otherwise the threads stay alive. 

someOperation se define entonces como un exigible

class someOperation extends Callable<SomeOtherClass> { 

    private SomeClass input; 

    public someOperation(SomeClass input){ 
     this.input = input; 
    } 

    public SomeOtherClass call(){ 
     // Do your operation on 'input' here 
    } 
} 

Nota: No tenía ningún bloque try - catch aquí, pero tendrá que tener alguno. shutdown debe estar en el bloque finally. Simplemente no recuerdo qué arroja qué ATM, tu IDE debería ayudarte con eso.

0

Doug Lea jsr166y incluye el marco de horquilla/unión, que es perfecto para este tipo de cosas. Está diseñado para la descomposición paralela de trabajos intensivos de CPU como este, y es muy eficiente en eso.

Probablemente la forma más fácil de usarlo es con el nuevo Scala 2.9 parallel collections, ya que abstrae completamente su uso (para obtener una colección paralela en Scala simplemente agregue .par hasta el final).

Ambas soluciones tienen muchos tutoriales y ejemplos disponibles a través de Google.

Cuestiones relacionadas