并不是iprogress的每一个结果都是如此.来自于任务

本文关键字:来自于 任务 iprogress 每一个 结果 并不是 | 更新日期: 2023-09-27 18:15:59

考虑以下实现,一个方法接受一个IProgress<int>,迭代10000个对象。numbers数组变量返回10000个对象,但IProgress<int>只报告9970 - 9980个对象。每次运行都不一样,所以有些会"丢失"。

    protected async override Task<int[]> CollectDataAsyncImpl(IProgress<int> progress) {                
        return await Task.Run<int[]>(() => {
            var numbers = new List<int>();
            foreach (var idx in new Int32Range(1, 10000).AsEnumerable().Index()) {                                            
                numbers.Add(idx.Value);                    
                if (progress != null) {
                    progress.Report(idx.Value);
                }
            }
            return numbers.ToArray();
        });
    }

作为参考,下面是我运行的测试。它在第三个断言Assert.Equal(10000, result[9999]);时失败。

[Fact]
async void ReportsProgress() {            
    var sut = new IntegerCollector();
    var result = new List<int>();
    var output = await sut.CollectDataAsync(new Progress<int>(i => result.Add(i)));
    Assert.Equal(10000, output.Length);
    Assert.Equal(1, result[0]);
    Assert.Equal(10000, result[9999]);
}

显然我做错了什么,或者我不理解任务/线程的内部原理。我的IProgress<int>new Progress<int>(i => result.Add(i))的实现不正确吗?我应该使线程安全,如果是这样,我怎么做呢?

GitHub有你可以克隆的代码&如果需要测试:https://github.com/KodeFoxx/Kf.DataCollection/tree/master/Source/Kf.DataCollection

并不是iprogress的每一个结果都是如此.来自于任务

这可能是因为Progress<T>的实现方式。当创建时,Progress<T>捕获同步上下文并使用它来执行i => result.Add(i)。由于您正在运行一个测试,所以我假设没有同步上下文。在本例中,Progress<T>使用默认的SynchronizationContext,它将工作项发布到线程池(ThreadPool.QueueUserWorkItem)。在线程池处理所有队列项之前,任务就完成了,这很好地解释了结果不一致的原因。

检查这种情况的简单方法:将IProgress<int>参数更改为Action<int>,并直接传递i => result.Add(i)委托,而不使用Progress<T>包装。