簡體   English   中英

在多線程Java程序中計時遠程調用

[英]Timing a remote call in a multithreaded java program

我正在編寫一個壓力測試,它將向遠程服務器發出許多呼叫。 我想在測試后收集以下統計信息:

  1. 遠程呼叫的延遲(以毫秒為單位)。
  2. 遠程服務器每秒可以處理的操作數。

我可以成功獲得(2),但是我遇到了(1)問題。 我當前的實現與另一個SO問題中顯示的實現非常相似。 我在那個問題中描述了同樣的問題:使用System.currentTimeMillis()報告的延遲時間比使用多個線程運行測試時的預期時間要長。

我分析了問題,並確定問題出在線程交織上(請參閱我對上面鏈接的另一個問題的回答以獲取詳細信息),並且System.currentTimeMillis()不是解決此問題的方法。

看來我應該能夠使用java.lang.management做到這一點,它具有一些有趣的方法,例如:

  1. ThreadMXBean.getCurrentThreadCpuTime()
  2. ThreadMXBean.getCurrentThreadUserTime()
  3. ThreadInfo.getWaitedTime()
  4. ThreadInfo.getBlockedTime()

我的問題是,即使我已經閱讀了API,但仍不清楚這些方法中的哪一種可以滿足我的需求。 在我鏈接的另一個SO問題的上下文中,這是我需要的:

long start_time = **rightMethodToCall()**;

result = restTemplate.getForObject("Some URL",String.class);
long difference = (**rightMethodToCall()** - start_time);

這樣,即使在多線程環境中,該difference使我可以很好地近似到遠程調用所花費的時間。

限制:我想避免使用synchronized塊來保護該代碼塊,因為我的程序還有其他線程希望繼續執行。

編輯:提供更多信息。

問題是這樣的:我想為遠程呼叫計時,而只是為遠程呼叫計時。 如果我使用System.currentTimeMillisSystem.nanoTime() ,並且如果我的線程多於內核,那么我有可能使該線程交錯:

  1. 線程1:較長的啟動時間...
  2. 線程1:結果= ...
  3. 線程2:較長的啟動時間...
  4. 線程2:結果= ...
  5. 線程2:長相差...
  6. 線程1:長差...

如果發生這種情況,則Thread2計算出的差是正確的,但Thread1計算出的差是不正確的(它將大於應有的差)。 換句話說,為了測量Thread1中的差異,我想排除第4行和第5行的時間。這是否該線程正在等待?

以不同的方式總結問題,以防其他人更好地理解它(這是@ jason-c在他的評論中的說法):

[我正在嘗試為遠程調用計時,但是使用多個線程運行測試只是為了增加測試量。

使用System.nanoTime() (但請參見此答案末尾的更新)。

您絕對不希望使用當前線程的CPU或用戶時間,因為用戶感知的延遲是掛鍾時間,而不是線程CPU時間。 您也不想使用當前線程的阻塞或等待時間,因為它會測量每個線程的爭用時間,而這也不能准確地表示您要測量的內容。

System.nanoTime()將返回相對准確的結果(盡管從技術上講,粒度僅保證與currentTimeMillis()或更好currentTimeMillis() ,但實際上,粒度往往要好得多,通常使用硬件時鍾或其他性能計時器來實現,例如QueryPerformanceCounter on Windows或Linux上的clock_gettime ),並使用具有固定參考點的高分辨率時鍾,將准確測量您要測量的內容。

long start_time = System.nanoTime();
result = restTemplate.getForObject("Some URL",String.class);
long difference = (System.nanoTime() - start_time);
long milliseconds = difference / 1000000;

System.nanoTime()確實有其自身的問題,但請注意不要被妄想症所困擾 對於大多數應用來說,這已經足夠了。 例如,當您將音頻樣本發送到硬件或其他東西時,您只是不想使用它來精確計時(無論如何您都不會直接在Java中這樣做)。

更新1:

更重要的是,您如何知道測量值比預期更長? 如果您的測量顯示了真實的時鍾時間,並且某些線程所花費的時間比其他線程長,那么這仍然是用戶感知的延遲准確表示 ,因為某些用戶經歷更長的延遲時間。

更新2(基於注釋的澄清):

我上面的大部分答案仍然有效。 但是出於不同的原因。

使用每個線程的時間並不能給您准確的表述,因為在遠程請求仍在處理時,線程可能處於空閑/不活動狀態,因此,即使是感知到的延遲的一部分,您也可以從測量中排除該時間。

遠程服務器引入了更多的不准確性,需要花費更長的時間來處理您同時發出的請求-這是您要添加的一個額外變量(盡管可以接受,代表遠程服務器正忙)。

掛牆時間也不是完全准確的,因為如您所見,本地線程開銷的變化可能會增加額外的延遲,這在單請求客戶端應用程序中通常不存在(盡管這可以接受作為代表客戶端應用程序的代表)多線程,但這是您無法控制的變量)。

在這兩個時間中,壁掛時間仍然比每個線程的時間更接近實際結果,這就是為什么我在上面留下了前面的答案。 您有幾種選擇:

  • 您可以按順序在單個線程上進行測試- 最終,這是達到指定要求的最准確方法
  • 您創建的線程數不能超過內核數,例如,固定大小的線程池具有對每個內核的綁定親和力(tricky: Java線程相似性 ),並且在每個任務上作為任務運行。 當然,由於底層機制的同步超出了您的控制范圍,因此仍然會添加任何變量。 可以降低交錯的風險(尤其是如果您設置了親和力),但是您仍然無法完全控制JVM正在運行的其他線程或系統上其他不相關的進程。
  • 您可以測量遠程服務器上的請求處理時間。 當然,這不會考慮網絡延遲。
  • 您可以繼續使用當前方法,並對結果進行一些統計分析,以消除異常值。
  • 您根本無法衡量它,只需進行用戶測試並等待對其發表評論,然后再嘗試對其進行優化(即與一直在為您開發的人一起衡量)。 如果對此進行優化的唯一原因是針對UX,則很可能是用戶擁有愉快的體驗,並且等待時間是完全可以接受的。

另外,這些都不能保證系統上其他不相關的線程不會影響您的計時,所以這就是為什么a)多次運行測試並進行平均(顯然)和b)設置可接受的值很重要的原因對時序誤差的要求是您可以接受的(您真的需要知道例如0.1ms的精度嗎?)。

就個人而言,我要么做第一個單線程方法,讓它運行一整夜或一個周末,要么使用您現有的方法,從結果中去除異常值,並接受時間上的誤差。 您的目標是在令人滿意的誤差范圍內找到現實的估計 在確定可接受的內容時,您還需要考慮最終將使用此信息做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM