2012-08-30 3 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 서버에서 응용 프로그램을 실행 한 후 1-2 일이 지나간 것으로 보입니다.

추가 설명 : 청크를 사용하여 바이트를 읽으므로 너무 많은 바이트를 읽고 버퍼에 저장할 수 있습니다. 따라서 공유 버퍼를 사용하여 다음 줄을 읽는 데 다시 사용할 수 있습니다. 일단 라인이 완전히 읽혀지면 버퍼에서 그것을 제거합니다.

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와 유사한 플러딩이나 매우 큰 데이터를 보내는 클라이언트 일 수 있습니다. –