2012-08-30 20 views
1

我寫了下面的C#功能:功能讀取線被阻斷

static string ReadLineCRLF(System.IO.Stream Stream, ref byte[] sharedBuffer, int bufferSize = 1024) 
{ 
    StringBuilder responseString = new StringBuilder(""); 
    string returnString = ""; 
    byte[] buffer = new byte[bufferSize]; 
    bool stopreading = false; 
    bool firstexecution = true; 
    while (!stopreading) 
    { 
     int readBytes; 
     if (firstexecution && sharedBuffer.Length > 0) 
     { 
      readBytes = sharedBuffer.Length; 
      sharedBuffer.CopyTo(buffer, 0); 
     } 
     else 
     { 
      readBytes = Stream.Read(buffer, 0, bufferSize); //BLOCKING HERE 
     } 
     firstexecution = false; 
     if (readBytes > 0) 
     { 
      int crIndex = Array.IndexOf(buffer, (byte)13); //13 = ASCII value for a carriage return 
      if (crIndex > -1 && Array.IndexOf(buffer, (byte)10, crIndex + 1) == crIndex + 1) //10 = ASCII value for line feed 
      { 

       stopreading = true; 
       sharedBuffer = readBytes - crIndex - 2 > 0 ? ArraySlice<byte>(buffer, crIndex+2, readBytes-crIndex-2) : new byte[] { }; 
       readBytes = crIndex; 
      } 
      if (readBytes > 0) 
      { 
       responseString.Append(System.Text.Encoding.ASCII.GetString(buffer, 0, readBytes)); 
      } 
      if (stopreading) 
      { 
       returnString = responseString.ToString(); 
      } 
     } 
     if (!stopreading && readBytes <= 0) 
     { 
      returnString = null; 
      stopreading = true; 
      sharedBuffer = new byte[] { }; 
     } 
    } 
    return returnString; 

} 

此功能是根據我的籌碼資源管理器,使用了大量的電腦性能在readBytes = Stream.Read(buffer, 0, bufferSize);阻塞。這個函數應該做的唯一事情就是從一個只由CRLF(「\ r \ n」)結束的流中讀取一行。

根據MSDNStream.Read返回less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.,它通常應該阻止並不會耗盡CPU性能。 The implementation will block until at least one byte of data can be read, in the event that no data is available. Read returns 0 only when there is no more data in the stream and no more is expected (such as a closed socket or end of file)

那麼爲什麼它 - 根據我的CLR堆棧資源管理器 - 使用瞭如此多的性能(高達70%)?我沒有看到任何邏輯錯誤,我認爲它應該等到某些字節可以被接收。似乎這種行爲並不總是發生,但在Windows服務器上開始執行應用程序一兩天後。

其他說明: 由於使用塊讀取字節,可能會有太多的字節被讀取並存儲在緩衝區中。因此我使用共享緩衝區,允許它再次使用它來繼續閱讀下一行。一行完全讀取後,我將其從緩衝區中刪除。

的ArraySlice功能如下:

public static T[] ArraySlice<T>(T[] data, int index, int length) 
{ 
    T[] result = new T[length]; 
    Array.Copy(data, index, result, 0, length); 
    return result; 
} 
+0

爲什麼不簡單地使用StreamReader?它會給你你需要的線。 –

+0

因爲一條線必須完全以CRLF結束。 'StreamReader.ReadLine'也接受簡單的CR和LF。這是因爲一些RFC規範。 –

回答

1

你怎麼知道Read阻止,而不是僅僅考慮了一會兒做什麼需要?

IO很昂貴;我期望完全可以預計,在這種方法中花費的大量時間在Read調用中。你說的70%聽起來是正確的。你看起來並沒有濫用這個方法,所以閱讀時間的百分比越高意味着執行其他任何事情的開銷就越低。我認爲讀者不會認爲它失去了70%的閱讀時間,而是因爲失去30%的時間從事非閱讀活動。不是一個不好的數據,但也沒有改進的餘地。

在深入研究之前,請確保您沒有處於微觀優化領域。我現在可以告訴你,它看起來並不像你所做的一切都是錯誤的,所以除非你已經對你的代碼進行了基準測試,並確定它的運行速度慢於你的需求所能接受的速度,只是不要擔心性能。如果你的程序執行速度不夠快,那麼你需要從現在開始的多長時間開始,需要多長時間才能「足夠快」。

+0

我不介意它是否在幾秒鐘內使用70%。但它似乎持續無限。我必須明天再看一遍,因爲到現在爲止它一直運行良好。問題是我不能重現這個問題,我不知道它發生的情況。由於我的功能是從網絡流中讀取數據,因此可能是類似DoS的泛濫或客戶端發送非常大的數據。 –