Java ExecutorService - 扩展

时间:2011-11-29 07:50:49

标签: java multithreading executorservice threadpoolexecutor forkjoinpool

我正在尝试使用ExecutorService及其函数invokeAll在Java中编写程序。我的问题是:invokeAll函数是否同时解决了这些问题?我的意思是,如果我有两个处理器,同时会有两个工人?因为aI无法使其正确缩放。如果我提供newFixedThreadPool(2)或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是一个实现Callable的类,wp是Partial Solutions的一个向量,一个在不同时间保存一些信息的类。

为什么不缩放?可能是什么问题?

这是PartialSolution的代码:

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;
        }    
    }
}

这是Map的代码:

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;
    }
}

所以在Map中我从片段中取出每一行并搜索每个表达式的出现次数,我也保存了行数。处理完所有片段后,在相同的PartialSolution中,我将信息保存在哈希映射中并返回新的PartialSolution。在下一步中,我将PartialSolutions与相同的fileName结合起来,并将它们引入Callable类Reduce,它与map相同,区别在于它进行其他操作,但也返回PartialSolution。

这是运行Map任务的代码:

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的任务,在列表中我获取它们。我不知道如何读取JVM线程转储。我希望我给你的信息足够好。如果有帮助,我在NetBeans 7.0.1中工作。

谢谢你, 亚历

3 个答案:

答案 0 :(得分:2)

  

我想知道的是,如果方法invokeAll,如果我创建了10个线程的ExcutorService,将同时解决10个任务或一次解决一个?

如果您向具有十个线程的ExecutorService提交十个任务,它将同时运行它们。他们是否可以完全平行并且彼此独立取决于他们正在做什么。但他们每个人都有自己的主题。

  

另一个问题,如果我说list.get(i).get()这将在它解决后返回PartialSolution?

是的,它会阻塞直到计算完成(如果没有完成)并返回其结果。

  

我真的不明白为什么如果我使用2个线程代替1,时间不会改善。

我们需要查看更多代码。他们是否在某些共享数据上同步?这些任务需要多长时间?如果它们非常短,您可能不会注意到任何差异。如果它们需要更长时间,请查看JVM线程转储以验证它们是否都在运行。

答案 1 :(得分:0)

如果使用两个线程创建线程池,则将同时运行两个任务。

我看到有两件事可能导致两个线程占用与一个线程相同的时间。

如果只有一个Map任务占用了大部分时间,那么额外的线程将不会使一个任务运行得更快。它不能比最慢的工作更快地完成。

另一种可能性是您的地图任务经常从共享向量中读取。这可能导致足够的争用,以消除两个线程的收益。

你应该在jvisualvm中提出这个问题,看看每个线程在做什么。

答案 2 :(得分:0)

Java 8在Executors - newWorkStealingPool中引入了另外一个API来创建工作窃取池。您不必创建RecursiveTaskRecursiveAction,但仍可以使用ForkJoinPool

public static ExecutorService newWorkStealingPool()
  

使用所有可用处理器作为目标并行级别创建工作窃取线程池。

默认情况下,它会将CPU核心数作为并行参数。如果您有核心CPU,则可以有8个线程来处理工作任务队列。

<强> 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.

ExecutorService或。{        ForkJoinPool或        如果您没有共享数据和共享锁定(同步)以及线程间通信,那么ThreadPoolExecutor性能会很好。如果所有任务在任务队列中彼此独立,则性能将得到改善。

ThreadPoolExecutor构造函数,用于自定义和控制任务的工作流程:

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

查看相关的SE问题:

How to properly use Java Executor?

Java's Fork/Join vs ExecutorService - when to use which?