2013-06-03 2 views
6

를 사용하는 동안 : 내가 비동기 MemoryStream로 작성 Stream을 읽으려고하고 있지만, Do...while 루프가 휴식 실패무한 마 ... 루프 내가 다음 코드 한 비동기 기다리고 있습니다

public static async Task<string> ReadLineAsync(this Stream stream, Encoding encoding) 
{ 
byte[] byteArray = null; 
using (MemoryStream ms = new MemoryStream()) 
{ 
    int bytesRead= 0; 
    do 
    { 
     byte[] buf = new byte[1024]; 
     try 
     { 
      bytesRead = await stream.ReadAsync(buf, 0, 1024); 
      await ms.WriteAsync(buf, 0, bytesRead); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message + e.StackTrace); 
     } 
    } while (stream.CanRead && bytesRead> 0); 

    byteArray = ms.ToArray(); 
    return encoding.GetString(ms.ToArray()); 
} 

. 나는 그것이 무한 루프라는 것을 의미한다. 어떻게 해결할 수 있을까요?

+1

디버거에서 사용해 보셨습니까? –

+1

UI 컨텍스트에서이 메서드에서 생성 된 작업에 대해 '대기'또는 '결과'를 호출 하시겠습니까? 그렇다면 교착 상태가 발생합니다. – Servy

+2

매번 처음 1024 바이트의 스트림을 읽고 다음 바이트 세트로 이동하지 않습니까? –

답변

0

CanRead가 true이고 bytesRead가 0 이상이면 루프 조건이 실행되도록 설정되어 있습니다. CanRead는 파일을 읽을 수있는 경우 항상 true입니다. 즉, 읽는 동안 바이트가 항상 0보다 커야합니다. 읽을 수있는 최대 바이트 수와 최소한의 다른 컨트롤을 설정해야합니다.

+0

에서 논의했습니다. Stream.CanRead는 그 목적으로 만 사용됩니다. 우리는 그것을 수동으로하지 않아도됩니다. –

+0

당신 말이 맞습니다. 나는 올바르게 말하지 않았습니다. 나는 그것을 편집했다. – MichelleJS

5

첫째, 예외적 인 상황에서 루프가 무기한 계속됩니다. 예외를 포착하고 무시해서는 안됩니다.

두 번째로 스트림이 실제로 이 아닌 경우 bytesRead은 절대로 0이되지 않습니다. 메서드의 이름 (ReadLineAsync)이 스트림의 끝까지 읽을 수 있다는 것을 내게 암시하지 않기 때문에 이것이 맞는 것 같습니다.

P. CanRead은 특정 스트림에 대해 변경되지 않습니다. 읽기 작업을 수행하는 스트림에 의미 론적 의미가 있는지 여부가 아닌지 여부는 지금을 읽을 수 있는지 여부가 아닙니다.

+0

아,하지만 내 스트림은 유한 한 시간에 끝납니다. –

+0

그런 다음 최소한의 재현을 게시하십시오. –

+0

* 당신의 스트림은 * 결말 *일까요? IMAP 연결은 일반적으로 여러 명령과 응답에 대해 보관됩니다. –

0

나는 당신의 방법을 데리고 다음 호출 예상대로

public static async Task<string> ReadLineAsync(this Stream stream, Encoding encoding) 
    { 
     const int count = 2; 
     byte[] byteArray = Enumerable.Empty<byte>().ToArray(); 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      int bytesRead = 0; 
      do 
      { 
       byte[] buf = new byte[count]; 
       try 
       { 
        bytesRead = await stream.ReadAsync(buf, 0, count); 
        await ms.WriteAsync(buf, 0, bytesRead); 
        Console.WriteLine("{0:ffffff}:{1}:{2}",DateTime.Now, stream.CanRead, bytesRead); 
       } 
       catch (Exception e) 
       { 
        Console.WriteLine(e.Message + e.StackTrace); 
       } 
      } while (stream.CanRead && bytesRead > 0); 

      byteArray = ms.ToArray(); 
      return encoding.GetString(byteArray); 
     } 
    } 

하지만 기본적으로이 일을 몇 가지 디버그 문을 읽기 버퍼 크기를 단축하고 추가하여 단지 약간 그것을 수정 :

private static void Main(string[] args) 
    { 
     FileStream stream = File.OpenRead(@"C:\in.txt"); 
     Encoding encoding = Encoding.GetEncoding(1252); 
     Task<string> result = stream.ReadLineAsync(encoding); 
     result.ContinueWith(o => 
      { 
       Console.Write(o.Result); 
       stream.Dispose(); 
      }); 

     Console.WriteLine("Press ENTER to continue..."); 
     Console.ReadLine(); 
    } 

그래서 당신의 입력 파일로 뭔가 될 수 궁금해? 광산

one 
two 
three 

(메모장 ++에서 윈도우 1252으로 인코딩) 한 내 출력은 어떻게

Press ENTER to continue... 
869993:True:2 
875993:True:2 
875993:True:2 
875993:True:2 
875993:True:2 
875993:True:2 
875993:True:2 
875993:True:1 
875993:True:0 
one 
two 
three 

참고했다 "Enter를 눌러서 계속 ..."주요 방법 때문에 예상대로 먼저 인쇄 된 비동기 적으로 호출되었고 CanRead은 파일이 읽을 수 있음을 나타 내기 때문에 항상 true입니다. 커서가 EOF에있는 것을 의미하는 것이 아니라 파일이 열린 상태입니다.

+0

위의 설명에 지정된대로 인코딩은'Encoding.GetEncoding (1252); –

+0

입니다. Windows-1252를 사용해 보았습니다. . 아직 예상되는 결과가 있습니다. 스트림에서 파일을 읽으려고한다고하니? 또는 웹 요청과 같은 것? –

+0

IMAP 서버에서 .. –

0

그래서 IMAP에서 스트림을 가져 오는 중입니다.이 방법은 해당 증기를 텍스트로 변환하는 것입니까?
SteamReader를 스트림 주위에 구성하고 ReadToEndAsync 또는 ReadToEnd 만 호출하면 어떨까요? 이 스트림을 비동기 작업으로 만드는 필요성을 의심합니다. 스트림이 전자 메일과 비슷한 경우 사용자가 읽는 동안 UI가 차단되는 것을 사용자가 눈치 채지 못할 정도로 커지지는 않습니다.
의견에서 알 수 있듯이 UI 앱이 아닌 경우 문제가 될 수 있습니다.

내 가정이 틀린 경우이 기능의 사용 방법에 대한 추가 정보를 묻는 질문을 할 수 있습니다. 더 많은 정보를 주시면 더 나은 답변을 얻을 수 있습니다.

EDIT : 코드에서 줄 끝 부분을 찾을 수는 없지만 사용자의 메서드가 ReadLineAsync라는 것을 알게되었습니다. 텍스트 줄을 읽으려는 의도가 있다면 SteamReader는 ReadLine 및 ReadLineAsync도 제공합니다. 코드는 다음을 수행하려고처럼 내 POV에서

+0

사실,이 코드는 속도와 비동기를 위해 멀티 테넌트 (multi-tenant) 앱에서 사용됩니다. 여기서 IMAP에서 스트림을 가져 오는 중입니다.이 메서드는 스트림을 지정된 인코딩으로 문자열로 변환하는 것입니다. Encoding.GetEncoding (1252); '. –

+0

비동기가 반드시 더 빠를 필요는 없습니다. 나는 정말 당신이 멀티 테넌트 앱의 의미를 이해하지 못한다. 이것은 일종의 서버 구성 요소입니까? 그렇다면 스레드 풀이이 작업을 확장하는 더 좋은 방법을 제공 할 수 있습니다. – pipTheGeek

0

은 같습니다

  • 1024 옥텟 청크의 순서로 전체 스트림을 읽을
  • 의 (a MemoryStream로 모든 청크를 연결하여, 어떤 바이트 배열을 보조 저장소로 사용)
  • 지정된 인코딩
  • 을 사용하여 MemoryStream을 MemoryStream으로 변환하여 호출자에게 반환합니다.

이것은 ... 나에게 복잡해 보입니다. 어쩌면 내가 누락되었지만 asyncawait을 사용하려면 VS2012 및 .Net 4.5 또는 VS2010을 사용해야합니다. 닷넷 4.0과 비동기 CTP, 그렇지? 그렇다면 왜 StreamReaderStreamReader.ReadToEndAsync() 방법을 사용하지 않는 것이 좋을까요?

public static async Task<string> MyReadLineAsync(this Stream stream, Encoding encoding) 
{ 
    using (StreamReader reader = new StreamReader(stream , encoding)) 
    { 
    return await reader.ReadToEndAsync() ; 
    } 
} 

중첩 I/O 아이디어 좋지만 메모리 스트림에 기입하는데 필요한 시간은 실제 peform받는 필요한 시간에 대하여 차이의 하나 엉 있도록 최소한 충분하지 말이며 I/O (아마도 당신의 입력 스트림이 디스크 나 네트워크 I/O를하고있다).

+0

코드가 컴파일되지 않습니다. 'return await reader를 의미 했습니까? ReadToEndAsync();'? – svick

+0

왜 이것이 3 개의 downvotes를 얻었습니까? 간단한 컴파일 오류 외에도이 답변에는 아무런 문제가 없습니다. (수정의 자유를 취했습니다) –

+0

@IsakSavo 여러분이 수정 한 방식은 잘못되었습니다. 이렇게하면'ReadToEndAsync()'가 실제로 완료되기 전에'reader'가'Dispose()'될 것입니다. 따라서 컴파일 오류는 그렇게 간단하지 않습니다. – svick