系统.执行错误的调用顺序

本文关键字:调用 顺序 错误 执行 系统 | 更新日期: 2023-09-27 18:15:07

我试图使用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) );
    }
}

假设订阅是这样的:

var progress = new Progress<int>();
progress.ProgressChanged += (sender, i) => Console.WriteLine(i);
client.Download(file, progress).Wait();

但结果是进度顺序不一致,如下所示:10、20、30、70、15、90、100、80.

这是一个默认委托的行为,还是有其他原因?

系统.执行错误的调用顺序

Progress<T>.Report为异步;我的意思是,Report方法在返回之前不会同步引发ProgressChanged事件。

Progress<T>类捕获SynchronizationContext,并将ProgressChanged事件的调用发送到捕获的上下文。

当在单线程环境中使用时,如Winforms, Wpf,你的代码将按预期工作。

在控制台应用程序中,不会有任何SynchronizationContext,因此Progress<T>将调用发送到默认的SynchronizationContext,该SynchronizationContext委托给ThreadPool。ThreadPool不保证任何顺序,这就是你看不到同步结果的原因。

我相信你是在控制台应用程序或类似的东西中测试这段代码,否则你的代码没有问题。

如果你需要一个同步版本的IProgress<T>,你必须滚动你自己的。