C# 异步下载不通过IProgress.Report报告
我面临着一个奇怪的问题,我必须承认——我不明白。我有一个任务,从Web异步下载一个文件:C# 异步下载不通过IProgress.Report报告,c#,windows-phone-8,asynchronous,async-await,windows-phone-8.1,C#,Windows Phone 8,Asynchronous,Async Await,Windows Phone 8.1,我面临着一个奇怪的问题,我必须承认——我不明白。我有一个任务,从Web异步下载一个文件: public async Task DownloadFile(Uri requestUri, string fileName, IProgress<int> progress) { HttpWebRequest request = HttpWebRequest.CreateHttp(requestUri); request.Method = "GET"; request.
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);
}
}
}
}
公共异步任务下载文件(Uri请求Uri、字符串文件名、IProgress进度)
{
HttpWebRequest-request=HttpWebRequest.CreateHttp(requestUri);
request.Method=“GET”;
request.AllowReadStreamBuffering=false;
使用(WebResponse=await request.GetResponseAsync())
使用(Stream mystr=response.GetResponseStream())
{
StorageFolder local=ApplicationData.Current.LocalFolder;
StorageFile file=await local.CreateFileAsync(文件名);
使用(Stream fileStream=await file.OpenStreamForWriteAsync())
{
const int BUFFER_SIZE=100*1024;
字节[]buf=新字节[缓冲区大小];
int字节读取=0;
//问题就在下面
而((bytesread=await mystr.ReadAsync(buf,0,BUFFER_SIZE))>0)
{
等待fileStream.WriteAsync(buf,0,字节读取);
进度报告(bytesread);
}
}
}
}
任务正在运行,但正如您所见,它应该报告其进度
问题是,当程序点击bytesread=await mystr.ReadAsync(buf,0,BUFFER\u SIZE)
行时,它不会在该线程上执行任何其他操作,直到整个文件下载完毕(不仅是BUFFER\u SIZE
)。在完成下载后,while
循环被触发了很多次,它需要从内存中复制流,这非常快
奇怪的是,相同的代码在WP8.0上运行时没有问题,现在我尝试在WP8.1上运行它,我面临这个问题。有人知道我做错了什么吗 需要记住的一件事是,
IProgress.Report
本身就是“异步的”。不是因为它返回了一个任务
,而是因为进度报告实现可能在报告
返回时没有完成其实际进度报告。特别是,Progress.Report
将在调用其委托或事件处理程序之前将进度报告封送到捕获的SynchronizationContext
通常,这正是您想要的:如果在UI线程上创建进度
,则其委托/事件处理程序将在UI线程上执行,并且在使用进度报告更新UI时,您不必担心跨线程封送
在本例中,我相信您看到的是WP8.1的一些攻击性缓存。微软一直在推动WP上的缓存。如果我的猜测是正确的,那么您看到的行为是由于同步完成的ReadAsync
(响应已经在HTTP缓存中)以及同步完成的WriteAsync
(缓冲文件写入)。在这种情况下,await
s中没有一个会实际产生,因此IProgress.Report
调用会堆积起来,等待在UI线程上运行
缓存通常只是开发过程中的一个“问题”。如果您确实希望最终用户遇到这种情况,则可以添加一个
wait Task.Yield()代码>进入你的循环。我认为你对缓存的猜测是正确的。我调试了更多,我看到的是程序在ReadAsync停止(可能将所有内容下载到缓存中),然后立即继续。我不知道在这种情况下该怎么办。我已经禁止ReadStreamBuffering,因此它应该可以工作(就像在WP8上一样)。如果要阻止缓存,则需要让服务器发送一个关闭缓存的缓存头,或者向URL附加一个唯一/随机值(并确保服务器忽略它).我已经试过了,问题不在于下载相同的Url,而是当程序点击行bytesread=wait mystr.ReadAsync(buf,0,BUFFER\u SIZE))
时,它会停止并等待整个文件从web下载,而不仅仅是BUFFER\u SIZE
,在下载之后,其余的操作在内存上执行得相当快。这确实是令人惊讶的行为。