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

上記のクラスには 2 つのデータ メンバーがdataありbloomFilterInstance、それら (参照) はメイン プログラムから渡されます。したがって、実際には data と BloomFilterInstance のインスタンスは 1 つしかなく、すべてのスレッドが同時にアクセスしています。

スレッドを起動するクラスは次のとおりです (無関係な詳細はほとんど省略されているため、すべての変数などは宣言されていると見なすことができます):

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 スレッドのスナップショットです。赤色はブロックされていることを示し、緑色は実行可能であり、黄色は待機中です。私の問題は、スレッドが一度に 1 つずつ実行されていることです。理由がわかりません。

注: これはスレッド セーフではないことはわかっていますが、今のところ読み取り操作のみを実行し、達成可能な生のパフォーマンスの向上を分析したいだけであることはわかっています。後で、より良いバージョンを実装します。

4

3 に答える 3

2

誰が私が逃した場所を教えてもらえますか

1 つの可能性は、スレッドを作成するコストが、計算を並列に実行することによるパフォーマンスの向上を圧倒していることです。質問に関連するコードが含まれていないため、これが実際の可能性であるかどうかはわかりません。

もう 1 つの可能性は、使用できるプロセッサ/コアが 1 つしかないことです。スレッドは、スレッドを実行するプロセッサがある場合にのみ実行されます。したがって、スレッド数による線形速度の期待値は、各スレッドの空きプロセッサである場合にのみ (理論的には) 達成される可能性があります。

最後に、すべてのスレッドが共有配列にアクセスしようとするため、メモリの競合が発生する可能性があります。適切な同期があれば、競合がさらに増える可能性があります。(注:あなたの例で競合が発生する可能性があるかどうかを判断するためのアルゴリズムを理解しようとはしていません。)


私の最初のアドバイスは、コードをプロファイリングして、それが洞察を提供するかどうかを確認することです。

また、パフォーマンスの測定方法を調べて、ベンチマーク アーティファクトだけが表示されていないことを確認してください。たとえば、JVM ウォームアップ効果。

于 2012-06-07T03:20:12.330 に答える
0

そのプロセスは CPU バウンドのようです。(I/O、データベース呼び出し、ネットワーク呼び出しなどはありません) 2 つの説明が考えられます。

  1. あなたのマシンにはいくつの CPU がありますか? Java はいくつ使用できますか? - スレッドが同じ CPU を求めて競合している場合は、調整作業を追加し、同じリソースにより多くの要求を課しています。
  2. メソッド全体の実行にかかる時間は? 非常に短い時間、コンテキスト切り替えスレッドでの追加の作業が実際の作業を圧倒する可能性があります。これに対処する方法は、より長い仕事をすることです。また、最初の数回の反復を数えずにループで何度も実行します (ウォームアップのように、代表的なものではありません)。
于 2012-06-07T03:18:50.053 に答える
0

いくつかの可能性が思い浮かびます:

  • bloomFilterInstanceの実装内で何らかの同期が行われています (これは指定されていません)。
  • ArrayList大量のメモリ割り当てが行われています。たとえば、 whenの不要なコピーと思われるものchkDataSetが作成され、 のnew Integer代わりに が使用されていInteger.valueOfます。メモリ割り当てのオーバーヘッド コストが発生している可能性があります。
  • あなたはCPUに縛られている可能性があり(bloomFilterInstance#contains高価な場合)、スレッドは実行する代わりに単にCPUをブロックしています。

プロファイラーは、実際の問題を明らかにするのに役立つ場合があります。

于 2012-06-07T03:21:00.883 に答える