c# - Not every result of IProgress<int> comes out of the task -
consider following implementation, method accepts iprogress<int>
, iterates on 10000 objects. numbers
array variable returns 10000 objects, iprogress<int>
reports between 9970 - 9980 objects. varies per run, "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 test ran. fails @ 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 wrong, or don't understand internals of task/threading. implementation of iprogress<int>
new progress<int>(i => result.add(i))
not correct? should make thread safe, , if so, how do that?
github has code can clone & test if need be: https://github.com/kodefoxx/kf.datacollection/tree/master/source/kf.datacollection
it because of how progress<t>
implemented. when created, progress<t>
captures synchronization context , uses execute i => result.add(i)
. since running test, assume there no synchronization context. in case progress<t>
uses default synchronizationcontext
, posts work items thread pool (threadpool.queueuserworkitem
). task completes before thread pool processes queued items, , explains results inconsistency.
a simple way check if case: change iprogress<int>
argument action<int>
, pass i => result.add(i)
delegate directly, without wrapping progress<t>
.
Comments
Post a Comment