2013-10-14 14 views
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都是巨大的列表,有數千到數十萬個項目。

+2

您究竟知道運行速度如何? – chrylis

+0

在第一個代碼片段中,您將列表'd'傳遞給'tally()',而在第二個代碼片段中傳遞列表項'datum'。這是一個版本還是其他版本的錯字? –

+0

不可能說爲什麼,因爲你沒有提供足夠的信息。 – david

回答

4

水貨版本應該只是速度更快,

這是一個常見的誤解。

但它的速度要慢一個數量級。

一個共同的結果

有什麼想法?

使用多線程有一個線程不具有的開銷。開銷可能比實際完成的工作高几個數量級,使得開銷慢得多。如果所做的工作比開銷大得多,則可以獲得非常好的可伸縮性。

例如假設將任務傳遞給另一個線程需要大約10微秒的時間。如果你的任務需要1微秒,開銷可能會導致你的表現失效。但是,如果任務需要100微秒,則可以看到顯着的性能改進並值得支付開銷的代價。

總之,沒有東西是免費的ESP不是多線程。

+0

是的,我明白這一點。但在這種情況下,它確實應該更快。當我在Python中執行它時,它會加快它的速度。 – rhombidodecahedron

+0

python比Java快多少?如果你的任務很慢,使用更多的線程有助於。你可以做的是每個處理器創建一個任務來完成一部分元素。 –

0

A)你排除了任何同步嗎?如果getChampoid在同步數據結構(如Hashtable)上點擊,我並不感到驚訝,性能急劇下降。

B)與Java,對象開銷通常是殺死性能。確保使用VisualVM等分析器。在你的情況下,如果你看到很多時間進入垃圾回收,我不會感到驚訝。

考慮將列表d劃分爲少量部分,然後在線程中處理每個部分。現在,對於每個datum,您將創建一個Runnable a Future對象,並且可能還有更多。當d很大時,對於垃圾收集器來說意味着很多工作(在這裏,它也不能被Hotspot優化)。

+0

A)getChampoid()讀取(但不寫入)列表c。但是,tally()方法已同步並需要寫入共享數組列表。 – rhombidodecahedron

+0

@EarlBellinger從多個線程寫入一個共享資源將比一個線程慢。你可以返回需要合併的結果,也就是說可以使用Callable。 –

+0

你走了,你有你的同步。只有一個人可以一次寫作,而其他人則會一直等到無所事事。有時候你可以解決這個問題,例如通過使用'AtomicIntegerArray'。但是,你能A)按照這篇文章中的建議分塊數據,B)爲每個線程分配一個獨立的存儲空間,然後有效地合併存儲空間? –

相關問題