我正在尝试使用HttpClient显示下载进度.为此,我使用System.Progress<T>.代码如下所示:
long totalRead = 0L;
var buffer = new byte[1024];
bool isMoreToRead = true;
ulong total = (ulong)response.Content.Headers.ContentLength;
while (isMoreToRead)
{
int read = await stream.ReadAsync(buffer, 0, buffer.Length);
if (read == 0)
isMoreToRead = false;
else
{
var data = new byte[read];
buffer.ToList().CopyTo(0, data, 0, read);
totalRead += read;
progress.Report((int) (totalRead*1d / total * 1d * 100) );
}
}
Run Code Online (Sandbox Code Playgroud)
假设订阅看起来像这样:
var progress = new Progress<int>();
progress.ProgressChanged += (sender, i) => Console.WriteLine(i);
client.Download(file, progress).Wait();
Run Code Online (Sandbox Code Playgroud)
但结果是,进度顺序不一致,如:10,20,30,70,15,90,100,80.
这是默认委托的行为,还是有另一个原因?
Progress<T>.Report是异步的; 我的意思是,Report方法不会ProgressChanged在返回之前同步引发事件.
Progress<T>class捕获SynchronizationContext并将ProgressChanged事件的调用发布到捕获的上下文.
在Winforms,Wpf等单线程上下文中使用时,您的代码将按预期工作.
在控制台应用程序中,不会有任何SynchronizationContext,因此Progress<T>将调用发布到委托给ThreadPool的默认SynchronizationContext.ThreadPool不保证任何订单,这就是你没有看到同步结果的原因.
我相信您正在使用Console应用程序或类似的东西测试此代码,否则您的代码没有任何问题.
如果你需要同步版本IProgress<T>,你必须自己动手.