2013-06-19 54 views
0

我正在使用由多個線程填充的LinkedBlockingQueue,項目數量很大(數千萬個對象)。LinkedBlockingQueue .take()性能

LinkedBlockingQueue.take()需要很多時間(通過分析器檢查) - 56%的時間。
隊列從不空!

什麼會影響take()方法的性能?

更新: 我在處理take()的結果的代碼中做了一些更改,我也將take()放入另一個線程,性能提高了近50%。

我不明白這是怎麼可能的,因爲我沒有改變推杆的任何邏輯...

UPDATE:

我打電話起飛前計次隊列數量已滿():
原始碼90%的呼叫隊列已滿。
通過改進的代碼,13%的調用隊列已滿。

+0

「把take()放到另一個線程中」是什麼意思?你能否給出一些代碼示例來顯示哪些線程在做什麼?整體表現或時間花在take()上的性能有所提高? – selig

+0

不幸的是,它是不可能的代碼,因爲關於性能的流程是複雜的 – user2479100

+0

,總體時間更好,因爲take()更好... – user2479100

回答

5

如果我們看代碼here,我們可以看到在獲取元素之前必須先進行鎖定。如果有很多線程正在使用,那麼這個鎖會有爭用 - 線程不會等待某些內容出現,而是等待其他線程處理。

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

編輯

在你有一個接受者和大量的推杆和隊列狀態越來越充分的瓶頸將成爲這段代碼

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

這需要給出signalNotFull()的情況下以putLock來表示隊列中現在有空間的事實。

+0

+1中完成以演示所涉及的代碼。 –

+0

只有一個線程需要() – user2479100

+0

你的隊列的固定大小? – selig

5

take()的重量相當輕,但如果調用足夠的話它將消耗大量的CPU。這聽起來像是你正在傳遞大量的對象,而這些對象對於消費者來說只需要很少的工作。我建議試着重組你的問題,這樣做更有效率。

例如,你可以,

  • 使用干擾器是專爲這類問題。
  • 發送塊/批數據例如一個對象列表,而不是許多單獨的對象。
  • 使用多個兌換器(對於少數作者罰款)
  • 如果您的目標是堅持數據,請使用類似Chronicle的內容。

這也有可能是你的個人資料不完全準確。當你測量一小段時間時,它可能會產生混合結果。

BTW:take()是單線程的。如果你有很多線程試圖同時調用take(),它們將互相阻塞。

+0

+1尤其適用於數據塊。 – Gray

+0

在一個線程 – user2479100