Pregunta

Estoy tratando de escribir un programa en Java usando ExecutorService y su función invokeAll. Mi pregunta es: ¿el invokeAll función resolver las tareas simultáneamente? Quiero decir, si tengo dos procesadores, ¿habrá dos trabajadores al mismo tiempo? Porque la IA no puede hacer que se escala correctamente. Tarda el mismo tiempo completar el problema si doy newFixedThreadPool(2) o 1.

List<Future<PartialSolution>> list = new ArrayList<Future<PartialSolution>>();
Collection<Callable<PartialSolution>> tasks = new ArrayList<Callable<PartialSolution>>();
for(PartialSolution ps : wp)
{
    tasks.add(new Map(ps, keyWords));
}
list = executor.invokeAll(tasks);

Map es una clase que implementa Callable y wp es un vector de soluciones parciales, una clase que contiene cierta información en diferentes momentos.

¿Por qué no escala? ¿Cual podría ser el problema?

Este es el código para parcialsolution:

import java.util.HashMap;
import java.util.Vector;

public class PartialSolution 
{
    public String fileName;//the name of a file
    public int b, e;//the index of begin and end of the fragment from the file
    public String info;//the fragment
    public HashMap<String, Word> hm;//here i retain the informations
    public HashMap<String, Vector<Word>> hmt;//this i use for the final reduce

    public PartialSolution(String name, int b, int e, String i, boolean ok)
    {
        this.fileName = name;
        this.b = b;
        this.e = e;
        this.info = i;
        hm = new HashMap<String, Word>();
        if(ok == true)
        {
            hmt = new HashMap<String, Vector<Word>>();
        }
        else
        {
             hmt = null;
        }    
    }
}

Un este es el código para el mapa:

public class Map implements Callable<PartialSolution>
{
    private PartialSolution ps;
    private Vector<String> keyWords;

    public Map(PartialSolution p, Vector<String> kw)
    {
        this.ps = p;
        this.keyWords = kw;
    }

    @Override
    public PartialSolution call() throws Exception 
    {
        String[] st = this.ps.info.split("\\n");
        for(int j = 0 ; j < st.length ; j++)
        {
            for(int i = 0 ; i < keyWords.size() ; i++)
            {
                if(keyWords.elementAt(i).charAt(0) != '\'')
                {
                    int k = 0;
                    int index = 0;
                    int count = 0;

                    while((index = st[j].indexOf(keyWords.elementAt(i), k)) != -1)
                    {
                        k = index + keyWords.elementAt(i).length();
                        count++;
                    }
                    if(count != 0)
                    {
                        Word wr = this.ps.hm.get(keyWords.elementAt(i));
                        if(wr != null)
                        {
                            Word nw = new Word(ps.fileName);
                            nw.nrap = wr.nrap + count;
                            nw.lines = wr.lines;
                            int grep = count;
                            while(grep > 0)
                            {
                                nw.lines.addElement(ps.b + j);
                                grep--;
                            }
                            this.ps.hm.put(keyWords.elementAt(i), nw);
                        }
                        else
                        {
                            Word nw = new Word(ps.fileName);
                            nw.nrap = count;
                            int grep = count;
                            while(grep > 0)
                            {
                                nw.lines.addElement(ps.b + j);
                                grep--;
                            }
                            this.ps.hm.put(keyWords.elementAt(i), nw);
                        }
                    }
                } 
                else
                {
                    String regex = keyWords.elementAt(i).substring(1, keyWords.elementAt(i).length() - 1);
                    StringBuffer sb = new StringBuffer(regex);
                    regex = sb.toString();
                    Pattern pt = Pattern.compile(regex);
                    Matcher m = pt.matcher(st[j]);
                    int count = 0;
                    while(m.find())
                    {
                        count++;
                    }
                    if(count != 0)
                    {
                        Word wr = this.ps.hm.get(keyWords.elementAt(i));
                        if(wr != null)
                        {
                            Word nw = new Word(this.ps.fileName);
                            nw.nrap = wr.nrap + count;
                            nw.lines = wr.lines;
                            int grep = count;
                            while(grep > 0)
                            {
                                nw.lines.addElement(ps.b + j);
                                grep--;
                            }
                            this.ps.hm.put(keyWords.elementAt(i), nw);
                        }
                        else
                        {
                            Word nw = new Word(this.ps.fileName);
                            nw.nrap = count;
                            int grep = count;
                            while(grep > 0)
                            {
                                nw.lines.addElement(ps.b + j);
                                grep--;
                            }
                            this.ps.hm.put(keyWords.elementAt(i), nw);
                        }
                    }
                }
            }
        }
        this.ps.info = null;
        return this.ps;
    }
}

Entonces, en el mapa, tomo cada línea del fragmento y busco cada expresión el número de apariencias y también guardo el número de línea. Después de procesar todo el fragmento, en la misma falta de parcia, guardo las informaciones en un mapa hash y devuelve la nueva solucencia parcial. En el siguiente paso, combino las soluciones parciales con el mismo nombre de archivo y las presento en una reducción de clase invocable, quién es lo mismo que el mapa, la diferencia es que realiza otras operaciones, pero devuelve también una falta de parcialidad.

Este es el código para ejecutar las tareas del mapa:

List<Future<PartialSolution>> list = new ArrayList<Future<PartialSolution>>();
Collection<Callable<PartialSolution>> tasks = new ArrayList<Callable<PartialSolution>>();
for(PartialSolution ps : wp)
{
   tasks.add(new Map(ps, keyWords));
}    
list = executor.invokeAll(tasks);

En la tarea, creo tarea de tipo mapa y en la lista los obtengo. No sé cómo leer el volcado de hilo JVM. Espero que sea lo suficientemente bueno qué información te di. Trabajo en NetBeans 7.0.1 si eso ayuda.

Gracias Alex

¿Fue útil?

Solución

Lo que quiero saber es si el método InvokeAnl, si creé el servicio ExcutorService con 10 hilos, resolverá 10 tareas al mismo tiempo o resolverá una a la vez?

Si envía diez tareas a un servicio de ejecutores con diez hilos, las ejecutará todas simultáneamente. Si pueden proceder completamente paralelos e independientes de uno, depende de lo que estén haciendo. Pero cada uno tendrá su propio hilo.

Y otra pregunta, si digo list.get (i) .get () esto devolverá la solucencia parcial después de que se resolviera?

Sí, bloqueará hasta que se realice el cálculo (si ya no se hace) y devolverá su resultado.

Realmente no entiendo por qué no mejora el tiempo si uso 2 hilos en lugar de 1.

Necesitamos ver más código. ¿Se sincronizan en algunos datos compartidos? ¿Cuánto tiempo tardan estas tareas? Si son muy cortos, es posible que no note ninguna diferencia. Si tardan más, mire el volcado de hilo JVM para verificar que todos se estén funcionando.

Otros consejos

Si crea el grupo de hilos con dos hilos, se ejecutarán dos tareas al mismo tiempo.

Hay dos cosas que veo que podrían estar causando que dos hilos tomen la misma cantidad de tiempo que un hilo.

Si solo una de sus tareas de mapa está tomando la mayor parte de su tiempo, entonces los hilos adicionales no harán que esa tarea se ejecute más rápido. No puede terminar más rápido que el trabajo más lento.

La otra posibilidad es que su tarea de mapa se lea de un vector compartido a menudo. Esto podría estar causando suficiente contención para cancelar la ganancia de tener dos hilos.

Debes mencionar esto en JVISUALVM para ver qué está haciendo cada hilo.

Java 8 ha introducido una API más en Ejecutores - NewWorkStealingPool Para crear trabajo robando la piscina. No tienes que crear RecursiveTask y RecursiveAction Pero aún puede usar ForkJoinPool.

public static ExecutorService newWorkStealingPool()

Crea un grupo de hilos de robo de trabajo utilizando todos los procesadores disponibles como su nivel de paralelismo objetivo.

Por defecto, tomará el número de núcleos de CPU como parámetro para el paralelismo. Si tiene CPU Core, puede tener 8 hilos para procesar la cola de tareas de trabajo.

Work stealing of idle worker threads from busy worker threads improves overall performance. Since task queue is unbounded in nature, this ForkJoinPool is recommended for the tasks executing in short time intervals.

O Servicio de ejecutor o Bifurcado o Threadpoolexecutor El rendimiento sería bueno si no tiene datos compartidos y bloqueo compartido (sincronización) y comunicación entre hilos. Si todas las tareas son independientes entre sí en la cola de tareas, el rendimiento mejorará.

ThreadPoolExecutor Constructor para personalizar y controlar el flujo de trabajo de las tareas:

 ThreadPoolExecutor(int corePoolSize, 
                       int maximumPoolSize, 
                       long keepAliveTime, 
                       TimeUnit unit, 
                       BlockingQueue<Runnable> workQueue, 
                       ThreadFactory threadFactory,
                       RejectedExecutionHandler handler)

Eche un vistazo a las preguntas de SE relacionadas:

¿Cómo usar correctamente el ejecutor de Java?

Java's Fork/Join vs Ejecutorservice - ¿Cuándo usar cuál?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top