0

私が使用LinkedBlockingQueueしているのは、複数のスレッドで満たされているため、アイテムの数が多い (数千万のオブジェクト)。

LinkedBlockingQueue.take()多くの時間がかかります (プロファイラーで確認) - 56% の時間。
キューが空になることはありません!!

take()メソッドのパフォーマンスに影響を与える可能性のあるものは何ですか?

更新: take() の結果を処理するコードにいくつかの変更を加えました。また、take() を別のスレッドに配置しました。パフォーマンスはほぼ 50% 向上しました。

パターのロジックを変更していないため、これがどのように可能かわかりません...

アップデート:

take() を呼び出す前に、キューがいっぱいになった回数を数えました。
元のコードでは、呼び出しキューの 90% がいっぱいでした。
改善されたコードでは、呼び出しキューの 13% がいっぱいでした。

4

2 に答える 2

5

take() はかなり軽量ですが、十分に呼び出すと大量の CPU を消費します。消費者にとってほとんど作業を必要としない多数のオブジェクトを渡しているようです。これがより効率的に行われるように、問題を再構築することをお勧めします。

たとえば、次のことができます。

  • この種の問題用に設計された Disruptor を使用してください。
  • 多くの個々のオブジェクトではなく、オブジェクトのリストなど、データのブロック/バッチを送信します。
  • 複数の Exchanger を使用する (ライターの数が少ない場合は問題ありません)
  • データを永続化することが目的の場合は、Chronicle などを使用してください。

また、プロフィールが完全に正確でない可能性もあります。短い期間を測定すると、さまざまな結果が得られる可能性があります。

ところで: take() はシングルスレッドです。同時に take() を呼び出そうとするスレッドが多数ある場合、それらは互いにブロックします。

于 2013-06-19T14:29:24.387 に答える
5

ここのコードを見ると、要素を取得する前にロックを取得する必要があることがわかります。多くのスレッドが取得している場合、このロックで競合が発生します。スレッドは何かが現れるのを待っているのではなく、他のスレッドが取得するのを待っています。

 public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            try {
                while (count.get() == 0)
                    notEmpty.await();
            } catch (InterruptedException ie) {
                notEmpty.signal(); // propagate to a non-interrupted thread
                throw ie;
            }

            x = extract();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

編集

1 人のテイカーと多数のパターがいて、キューがいっぱいになり続ける場合、signalNotFull()このコードによってボトルネックが発生します。

private void signalNotFull() {
    final ReentrantLock putLock = this.putLock;
    putLock.lock();
    try {
        notFull.signal();
    } finally {
        putLock.unlock();
    }
}

putLockこれは、キューに現在スペースがあるという事実を通知するために を取る必要があります。

于 2013-06-19T14:29:47.623 に答える