c# - Stung by using Linq deferred execution with async/await -
i new async/await , tinkering execute operation on list of objects using list of tasks. used linq generate both list of objects , list of tasks. example below looks little contrived, simplified version of actual code.
i found when code executed shown, after tasks have completed (after await), none of object's properties have been updated, , of tasks still have status of running.
i found eliminating linq deferred execution converting both objects , tasks actual lists via .tolist<>(), code worked expected (objects populated, tasks run completion).
i familiar linq deferred execution i'm confused (isn't) going on in code. i'm making noob mistake async/await...what it?
private class foo { public datetime { get; set; } } private void button_click( object sender, eventargs e ) { populatedates(); } private async void populatedates() { var ordinals = new list<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, }; var foos = ordinals.select( o => new foo() ); //.tolist(); var tasks = foos.select( f => populatedateasync( f ) ); //.tolist(); await task.whenall( tasks ); var firstnow = foos.elementat( 0 ).now; var firsttaskstatus = tasks.elementat( 0 ).status; } private task populatedateasync( foo foo ) { return task.run( () => populatedate( foo ) ); } private void populatedate( foo foo ) { thread.sleep( 2000 ); foo.now = datetime.now; }
your problem due linq's deferred execution. in particular, task.whenall
appropriately waiting tasks complete. however, when call elementat
, sequence re-evaluated, creating new foo
, task
.
so, not work:
var ordinals = new list<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, }; var foos = ordinals.select( o => new foo() ); //.tolist(); // first foo, creating it. var first = foos.elementat(0); // gets *different* foo. creates again. var other = foos.elementat(0); messagebox.show((first == other).tostring()); // displays "false"
in general, it's idea "reify" sequence (using toarray
or similar) when dealing operations side effects, including starting async
operations. task.whenall
reify sequence internally, if evaluate again (e.g., elementat
), unexpected behavior.
Comments
Post a Comment