0

나는 이상한 문제에 직면하고 있습니다. 나는 이해해야합니다. 나는 비동기 웹에서 파일을 다운로드하는 작업,했습니다 : 태스크가 작동비동기 다운로드는 IProgress를 통해보고하지 않습니다.보고

public async Task DownloadFile(Uri requestUri, string fileName, IProgress<int> progress) 
{ 
    HttpWebRequest request = HttpWebRequest.CreateHttp(requestUri); 
    request.Method = "GET"; 
    request.AllowReadStreamBuffering = false; 
    using (WebResponse response = await request.GetResponseAsync()) 
    using (Stream mystr = response.GetResponseStream()) 
    { 
     StorageFolder local = ApplicationData.Current.LocalFolder; 
     StorageFile file = await local.CreateFileAsync(fileName); 
     using (Stream fileStream = await file.OpenStreamForWriteAsync()) 
     { 
      const int BUFFER_SIZE = 100 * 1024; 
      byte[] buf = new byte[BUFFER_SIZE]; 
      int bytesread = 0; 
      // the problem is here below 
      while ((bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE)) > 0) 
      { 
       await fileStream.WriteAsync(buf, 0, bytesread); 
       progress.Report(bytesread); 
      } 
     } 
    } 
} 

,하지만 당신이 볼 수있는 그것의 진행 상황을보고해야합니다.

이 프로그램이 라인 bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE) 안타 때 문제가 있음을 밝혀 - 전체 파일 (뿐만 아니라 BUFFER_SIZE를) 다운로드 된 때까지 그 스레드에서 다른 작업을 수행하지 않습니다. 다운로드가 완료되면 while 루프가 여러 번 실행되어 메모리에서 스트림을 복사합니다. 이는 매우 빠르게 진행됩니다.

이상한 것은 같은 코드가 WP8.0에 문제없이 작업했다 지금은 WP8.1에서 실행하려고 나는이 문제에 직면하고있어 것입니다. 아무도 내가 뭘 잘못하고 있는지 생각하지 못하니? 명심해야 할

답변

2

한 가지 IProgress<T>.Report는 "비동기"자신을 것입니다. 다시 말해 Task을 반환한다는 의미는 아니지만 진행률보고 구현이 실제로 Report 반환까지 실제 진행보고를 수행하지 않았을 수도 있다는 의미에서 아닙니다. 특히 Progress<T>.Report은 대리자 또는 이벤트 처리기를 호출하기 전에 캡처 된 SynchronizationContext에 진행률 보고서를 마샬링합니다.

일반적으로 이것은 정확히 원하는 것입니다. UI 스레드에서 Progress<T>을 만든 경우 UI 스레드에서 해당 대리자/이벤트 처리기가 실행되므로 스레드 간 마샬링에 대해 걱정할 필요가 없습니다. 진행률 보고서로 UI를 업데이트합니다. 이 경우

, 나는 당신이보고있는 것은 WP8.1에 의해 일부 공격적인 캐싱 믿습니다. Microsoft는 실제로 WP에 대한 캐싱을 추진해 왔습니다. 내 추측이 맞다면, 당신이보고있는 동작은 (응답은 HTTP 캐시에 이미)뿐만 아니라 WriteAsync 동 기적으로 완료 (버퍼 파일 쓰기)로 인해 ReadAsync 동 기적으로 완료입니다. 이 경우 await 중 실제로 아무 것도 출력하지 않으므로 IProgress<T>.Report 호출은 UI 스레드에서 실행할 기회를 기다리고 있습니다.

캐싱은 일반적으로 개발하는 동안 단지 "문제"입니다. 최종 사용자에게이 상황이 발생할 것으로 예상되는 경우 루프에 await Task.Yield();을 추가 할 수 있습니다.

+0

캐싱에 대한 귀하의 추측은 맞다고 생각합니다. 필자가 보았을 때, 프로그램이 ReadAsync에서 멈추고 (아마 모든 것을 캐시로 다운로드 한 후) 즉시 진행된다는 것입니다. 나는 그런 경우에 해야할지 모르겠다. WPFS에서와 같이 이미 작동하도록 ReadStreamBuffering을 허용하지 않았습니다. – Romasz

+0

* 캐싱을 방지하려면 캐싱을 해제하는 캐싱 헤더를 서버에 보내거나 URL에 고유/임의 값을 추가하여 서버가 해당 캐싱을 무시하는지 확인해야합니다. –

+0

나는 이미 시도하고'멈출 기다린다는 전체 파일이 다운로드 될 때까지 문제가 동일한 URL을 다운로드하지,하지만 프로그램이 선을 칠 때'bytesread =이 mystr.ReadAsync (버피, 0, BUFFER_SIZE))를 기다리고 있습니다 웹에서 - 'BUFFER_SIZE'뿐만 아니라 나머지 작업을 다운로드 한 후 메모리에서 매우 빠르게 수행됩니다. – Romasz

관련 문제