2013-10-11 58 views
10

我正在爲二進制數據開發基於Java的下載程序。該數據通過基於文本的協議(UU編碼)傳輸。對於聯網任務,使用netty庫。二進制數據被服務器分成幾千個小數據包併發送到客戶端(即Java應用程序)。Java:字符串的更快替代方法(字節[])

netty每次收到新消息(數據)時,都會收到一個ChannelBuffer對象。現在我需要處理這些數據,除了需要檢查來自服務器的包的頭部之外,還需要執行其他任務(如HTTP狀態行)。爲此,我請撥打ChannelBuffer.array()以獲得byte[]陣列。然後,我可以通過new String(byte[])將該數組轉換爲字符串,並輕鬆檢查(例如比較)其內容(再次,就像比較HTTP中的「200」狀態消息)。

我寫的軟件是使用多個線程/連接,以便我並行地從netty接收多個數據包。

這通常工作正常,但是,在分析應用程序時,我注意到當與服務器的連接良好且數據進入速度非常快時,對String對象的轉換似乎是一個瓶頸。在這種情況下,CPU使用率接近100%,根據分析器花費的大量時間調用此構造函數String(byte[])

我搜索了一個更好的方法,從ChannelBufferString,並注意到前者也有一個toString()方法。但是,該方法甚至比構造函數更慢。

所以我的問題是:你們有沒有人知道一個更好的選擇,以實現我在做什麼?

+0

爲什麼?只需發送字節,儘可能快。忘記編碼;忘記分裂。 TCP已經分裂,並且它比當前知道更多關於當前連接的最佳數據包大小。 – EJP

回答

13

也許你可以完全跳過字符串轉換?您可以使用常量來保存比較值的字節數組,並檢查數組到數組而不是字符串到字符串。

這裏有一些快速代碼來說明。目前你正在做這樣的事情:

String http200 = "200"; 
// byte[] -> String conversion happens every time 
String input = new String(ChannelBuffer.array()); 
return input.equals(http200); 

也許這就是快:

// Ideally only convert String->byte[] once. Store these 
// arrays somewhere and look them up instead of recalculating. 
final byte[] http200 = "200".getBytes("UTF-8"); // Select the correct charset! 
// Input doesn't have to be converted! 
byte[] input = ChannelBuffer.array(); 
return Arrays.equals(input, http200); 
+1

+1創建字符串可能比您預期的要貴。避免創建它們,你可以顯着提高性能。 –

+0

這是一個很好的答案,非常感謝! – Matthias

1

一些檢查你正在做的可能只是看緩衝的一部分。如果您可以使用字符串構造函數的替代形式:

new String(byteArray, startCol, length) 

這可能意味着將很少的字節轉換爲字符串。

你在消息中尋找「200」的例子就是一個例子。

你可能會發現,你可以使用字節數組的長度爲線索。如果某些消息很長,而您正在尋找較短的消息,請忽略長消息並且不要轉換爲字符。或類似的東西。

隨着什麼@EricGrunzke說,在字節的緩衝區部分希望過濾掉一些消息,並發現你並不需要將它們從字節轉換爲字符。

如果你的字節是ASCII字符,如果你使用的字符集「ASCII」而不是任何的默認值是您的服務器轉換爲字符可能會更快:

new String(bytes, "ASCII") 

威力在這種情況下更快。

實際上,您可能可以選擇字符集進行字符轉換,以某種有組織的方式進行轉換,以加快速度。

0

取決於你正在嘗試做有幾個選項:

  1. 如果你只是想獲得響應狀態,那麼你就不能叫getStatus()?這可能比讓字符串出來更快。
  2. 如果你正在嘗試轉換緩衝區,那麼假設你知道它將是ASCII,這聽起來像你一樣,那麼就把數據保留爲byte [],然後將你的UUDecode方法轉換爲一個字節[]而不是一個字符串。

字符串轉換的最大代價很可能是將數據從字節數組複製到字符串的內部字符數組,這與轉換最有可能只是一堆工作不需要做。