2011-08-08 45 views

回答

1

多少時間在CPU切換線程,而不是運行 他們

  • 比方說,你有100萬FPU進行使用。
  • 以同步隊列加載它們(即,線程必須鎖定隊列時輪詢)
  • 設n是在裝置上的處理器的可用數目(哆= 2,等等)

然後在隊列中創建n個線程來執行所有的FPU。您可以使用System.currentTimeMillis()前後計算總時間。然後嘗試使用n + 1個線程,然後n + 2,n + 3等...

理論上,您擁有的線程越多,切換次數越多,處理所有應用程序的時間就越長FPU。它會給你一個非常粗略的轉換開銷的想法,但這很難衡量。

多少同步流量共享存儲器總線上創建 - 當線程共享數據,他們必須使用同步機制

我想創建10個線程通過使用發送每個10個000消息到另一個線程隨機100個消息的同步阻塞隊列。每個線程都會查看阻塞隊列以檢查消息是否適合他們,如果是,則將其拉出。然後,他們會嘗試在不阻塞的情況下推送消息,然後重複peek操作等等,直到隊列爲空並且所有線程都返回。

順便說一下,每個線程可能會成功推送和偷看/拉的數量與不成功的數量。然後,您會對同步流量中的有用工作和無用工作有一個大致的瞭解。再一次,這很難衡量。

當然,你也可以玩線程的數量或阻塞隊列的大小。

9

由於線程切換以及由於內存緩存爭用導致的浪費,您無法輕鬆區分浪費。您可以測量線程爭用。也就是說,在linux上,您可以cat/proc/PID/XXX並獲取大量詳細的每線程統計信息。但是,由於先發制人的調度器不會在腳中自行射擊,所以無論使用多少個線程,每秒不會超過30個ctx切換。而且這段時間會相對較短小vs你正在做的工作量..上下文切換的實際成本是緩存污染。例如一旦重新上下文切換,您很可能會大部分緩存未命中。因此,操作系統時間和上下文切換計數的值很小。

真正有價值的是線程間緩存線污垢的比例。根據CPU的不同,接下來是對等CPU讀取的高速緩存行是SLOWER,而不是高速緩存未命中 - 因爲在開始讀取之前,您必須強制對等CPU將其值寫入main-mem。 CPU讓你從同級高速緩存行中拉出而不會碰到main-mem。

因此,關鍵是絕對最小化ANY共享修改的內存結構。儘可能使所有內容爲只讀。這包括共享FIFO緩衝區(包括執行程序池)。即,如果您使用同步隊列 - 那麼每個sync-op是一個共享的髒內存區域。更重要的是,如果速率足夠高,它可能會觸發OS陷阱停頓,等待對等線程的互斥鎖。

理想的做法是分割RAM,將固定數量的工作人員分配給一個單獨的大工作單元,然後使用一個計數下拉鎖存器或其他內存屏障(使每個線程只觸摸一次)。理想情況下,任何臨時緩衝區都是預先分配的,而不是進入和退出共享內存池(這會導致緩存爭用)。 Java的'同步'模塊利用(後臺)共享哈希表內存空間,從而觸發不需要的髒讀取,我還沒有確定Java 5 Lock對象是否避免這種情況,但是您仍然利用獲得的OS分檔對你的吞吐量沒有幫助。很顯然,大多數OutputStream操作觸發這樣的同步調用(當然通常是填充一個公共流緩衝區)。

一般來說,我的經驗是單線程比通用字節數組/對象數組等等的多線程處理速度更快。至少使用了我嘗試過的簡單排序/過濾算法。在我的經驗中,Java和C都是如此。我還沒有嘗試FPU intesive操作(如divides,sqrt),其中cache-lines可能不是一個因素。

基本上,如果你是一個單獨的CPU,你就沒有緩存行問題(除非操作系統總是在共享線程中刷新緩存),但多線程購買你沒有什麼。在超線程中,這是一樣的交易。在單CPU共享L2/L3緩存配置(例如AMD)中,您可能會發現一些優勢。在多CP​​U Intel BUS中,忘記它 - 共享寫入內存比單線程差。

+0

如果您不想要設計應用程序,而只是簡單地衡量性能差異(重新閱讀您的問題)。然後希望算法可以線性劃分,然後傳遞給可配置數量的線程,其中1可能具有特殊的替代代碼路徑。然後只運行每個(可能具有pre-exit zip up/proc/self/*)。還使用記錄/報告每個線程的開始/結束的納米時間(而不是其三角)。 –

2

要衡量一個上下文切換多少時間我會運行類似以下內容:

public static void main(String[] args) {  
    Object theLock = new Object(); 
    long startTime; 
    long endtime; 
    synchronized(theLock){ 
     Thread task = new TheTask(theLock); 
     task.start(); 
     try { 
      theLock.wait(); 
      endTime = System.currentTimeMillis(); 
     } 
     catch(InterruptedException e){ 
      // do something if interrupted 
     } 
    } 
    System.out.println("Context Switch Time elapsed: " + endTime - startTime); 
} 

class TheTask extends Thread { 
    private Object theLock; 
    public TheTask(Object theLock){ 
     this.theLock = theLock; 
    } 
    public void run(){ 
     synchronized(theLock){ 
      startTime = System.currentTimeMillis(); 
      theLock.notify(); 
     } 
    } 
} 

您可能需要運行該代碼多次獲得一份平均,並確保這兩個線程是唯一那些在你機器上運行的(上下文切換隻發生在這兩個線程中)。

相關問題