0

我是多线程的新手,我必须使用多线程编写程序来提高效率。在我第一次尝试时,我所写的结果正好相反。这是我写的:

class ThreadImpl implements Callable<ArrayList<Integer>> { 
    //Bloom filter instance for one of the table
    BloomFilter<Integer> bloomFilterInstance = null;
    // Data member for complete data access.
    ArrayList< ArrayList<UserBean> > data = null;
    // Store the result of the testing 
    ArrayList<Integer> result = null;
    int tableNo;

    public ThreadImpl(BloomFilter<Integer> bloomFilterInstance, 
                        ArrayList< ArrayList<UserBean> > data, int tableNo) {
        this.bloomFilterInstance = bloomFilterInstance;
        this.data = data;
        result  = new ArrayList<Integer>(this.data.size());
        this.tableNo = tableNo;
    }

    public ArrayList<Integer> call() {
        int[] tempResult = new int[this.data.size()];
        for(int i=0; i<data.size() ;++i) {
            tempResult[i] = 0;
        }
        ArrayList<UserBean> chkDataSet = null;
        for(int i=0; i<this.data.size(); ++i) {
            if(i==tableNo) {
                //do nothing;
            } else {
                chkDataSet = new ArrayList<UserBean> (data.get(i));
                for(UserBean toChk: chkDataSet) {
                    if(bloomFilterInstance.contains(toChk.getUserId())) {
                        ++tempResult[i];
                    }
                }
            }
            this.result.add(new Integer(tempResult[i]));
        }
        return result;
    }
}

在上面的类中有两个数据成员databloomFilterInstance它们(引用)是从主程序传递的。所以实际上只有一个数据实例和bloomFilterInstance,并且所有线程都在同时访问它。

启动线程的类是(省略了一些不相关的细节,所以所有变量等你可以假设它们被声明):

class MultithreadedVrsion {
    public static void main(String[] args) {
        if(args.length > 1) {
            ExecutorService es = Executors.newFixedThreadPool(noOfTables);
            List<Callable<ArrayList<Integer>>> threadedBloom = new ArrayList<Callable<ArrayList<Integer>>>(noOfTables);
            for (int i=0; i<noOfTables; ++i) {
                threadedBloom.add(new ThreadImpl(eval.bloomFilter.get(i), 
                                                eval.data, i)); 
            }
            try {
                List<Future<ArrayList<Integer>>> answers = es.invokeAll(threadedBloom);
                long endTime = System.currentTimeMillis();
                System.out.println("using more than one thread for bloom filters: " + (endTime - startTime) + " milliseconds");
                System.out.println("**Printing the results**");
                for(Future<ArrayList<Integer>> element: answers) {
                    ArrayList<Integer> arrInt = element.get();
                    for(Integer i: arrInt) {
                        System.out.print(i.intValue());
                        System.out.print("\t");
                    }
                    System.out.println("");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

我使用 jprofiler 进行了分析,然后

![这里]:(http://tinypic.com/r/wh1v8p/6)

是 CPU 线程的快照,其中红色表示阻塞,绿色表示可运行,黄色表示正在等待。我的问题是线程一次运行一个我不知道为什么?

注意:我知道这不是线程安全的,但我知道我现在只会进行读取操作,并且只想分析可以实现的原始性能增益,稍后我将实现更好的版本。

4

3 回答 3

2

谁能告诉我错过了哪里

一种可能性是创建线程的成本超过了并行计算带来的任何可能的性能提升。我们无法确定这是否真的有可能,因为您没有在问题中包含相关代码。

另一种可能性是您只有一个处理器/内核可用。线程仅在有处理器运行时才会运行。因此,您对线程数的线性速度的期望只有在每个线程都有一个空闲处理器时才可能(理论上)实现。

最后,由于所有线程都试图访问共享数组,可能会出现内存争用。如果您有适当的同步,那可能会增加进一步的争用。(注意:我没有尝试理解算法来确定您的示例中是否可能存在争用。)


我最初的建议是分析你的代码,看看是否能提供任何见解。

并查看您测量性能的方式,以确保您不只是看到一些基准测试产品;例如 JVM 预热效果。

于 2012-06-07T03:20:12.330 回答
0

该进程看起来受 CPU 限制。(没有 I/O、数据库调用、网络调用等)我能想到两种解释:

  1. 你的机器有多少个 CPU?Java允许使用多少个?- 如果线程正在竞争相同的 CPU,则您增加了协调工作并对相同资源提出了更多需求。
  2. 整个方法运行需要多长时间?在很短的时间内,上下文切换线程中的额外工作可能会压倒实际工作。解决这个问题的方法是做一个更长的工作。此外,在不计算前几次迭代的循环中运行很多次(就像热身一样,它们不具有代表性。)
于 2012-06-07T03:18:50.053 回答
0

想到了几种可能性:

  • 的实现内部正在进行一些同步bloomFilterInstance(未给出)。
  • 有很多内存分配正在进行,例如,什么似乎是创建ArrayList时的不必要副本chkDataSet,使用 ofnew Integer代替Integer.valueOf. 您可能会遇到内存分配的间接成本。
  • 您可能受 CPU 限制(如果bloomFilterInstance#contains很昂贵),并且线程只是阻塞 CPU 而不是执行。

分析器可能有助于揭示实际问题。

于 2012-06-07T03:21:00.883 回答