Consider following implementation, a method accepts an IProgress<int>
, iterates over 10000 objects. The numbers
array variable returns 10000 objects, but the IProgress<int>
reports only between 9970 - 9980 objects. It varies per run, so some get "lost".
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();
});
}
As reference, here's the test I ran. It fails at the third assert 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]);
}
Clearly I'm doing something wrong, or I don't understand the internals of task/threading. Is my implementation of IProgress<int>
to new Progress<int>(i => result.Add(i))
not correct? Should I make that thread safe, and if so, how do I do that?
GitHub has the code which you can clone & test with if need be: https://github.com/KodeFoxx/Kf.DataCollection/tree/master/Source/Kf.DataCollection