0

一連の:

void do(List<D> d, final List<C> c) {
for (D datum : d)
    getChampoid(datum, c).tally(datum);

平行:

static final int procs = Runtime.getRuntime().availableProcessors();
static final ExecutorService pool = Executors.newFixedThreadPool(procs);
void do(List<D> d, final List<C> c) {
    List<Future> futures = new ArrayList<>();
    for (final D datum : d)
        futures.add(pool.submit(new Runnable() {

            @Override
            public void run() {
                getChampoid(datum, c).tally(datum);
            }

        }));
    for (Future f : futures)
        try {
            f.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

まったく同じことをしているように見えるので、困惑しています。並列バージョンの方が高速であるはずですが、桁違いに遅いです。何かご意見は?

参考までに、d と c は両方とも、数千から数十万のアイテムを含む巨大なリストです。

4

2 に答える 2

4

並列バージョンの方が高速である必要があり、

それはよくある誤解です。

しかし、それは桁違いに遅いです。

よくある結果

何かご意見は?

複数のスレッドを使用すると、1 つのスレッドにはないオーバーヘッドが発生します。オーバーヘッドは、実際に実行される作業よりも桁違いに大きくなり、作業が大幅に遅くなる可能性があります。実行される作業がオーバーヘッドよりもはるかに大きい場合、非常に優れたスケーラビリティを得ることができます。

たとえば、タスクを別のスレッドに渡すのに約 10 マイクロ秒かかるとします。タスクに 1 マイクロ秒かかる場合、オーバーヘッドによってパフォーマンスが低下する可能性があります。ただし、タスクに 100 マイクロ秒かかる場合は、パフォーマンスが大幅に向上し、オーバーヘッドの代償を支払う価値があることがわかります。

要するに、マルチスレッドではなく、何も無料ではありません。

于 2013-10-14T22:58:22.870 に答える
0

A) 同期を除外しましたか? getChampoid同期されたデータ構造 (Hashtable など) にヒットした場合、パフォーマンスが大幅に低下することは驚くことではありません。

B) Java では、通常、オブジェクトのオーバーヘッドがパフォーマンスを低下させます。VisualVM などのプロファイラーを必ず使用してください。あなたの場合、ガベージ コレクションに多くの時間がかかっても驚かないでしょう。

dリストを少数の部分に分割し、各部分をスレッドで処理することを検討してください。現時点では、すべてに対してオブジェクトdatumを作成します。これは、が大きい場合、ガベージ コレクターに多くの作業が必要になることを意味します (ここでは、Hotspot によって最適化することもできません)。Runnable Futured

于 2013-10-14T23:18:47.357 に答える