I am running task like below.
var tasks = from job in jobs select ProcessFile(job);
where ProcessFile is a method which return bool Task
private async Task<bool> ProcessFile(Job job)
Now weird thing is that i want to check if any of the task result was true or not like below.
await Task.WhenAll(tasks);
var isTrueForAny =tasks.Any(x => x.Result == true);
But at this point my method ProcessFile(job) is called again though i have only one job. Could you guys help me understand what is the reason?
The reason of that behaviour is Deferred Execution.
Deferred execution means that the evaluation of an expression is delayed until its realized value is actually required.
Let's take a look step by step:
var tasks = from job in jobs select ProcessFile(job);
See value of the tasks variable as sql query. It will be executed every time when you are trying to use tasks variable in places where value of that query is needed.
First time that "query" will be executed while awaiting that tasks.
await Task.WhenAll(tasks);
And second time, when you are iterating over the result of that query. Though, not all tasks will be executed twice as Any will stop iterating as soon as it findsfirst matched task.
var isTrueForAny =tasks.Any(x => x.Result == true);
Take a look to Deferred Execution concept in LINQ.
For solving the issue you need to force immediate execution.To force immediate execution of a query that does not produce a singleton value, you can call the ToList method, the ToDictionary method, or the ToArray method on a query or query variable. But, it will be problematic as you are projecting Task object from your collection. You can get around of that issue by just creating extension method ToListAsync.
Or for solving the issue, you just need to change your code in a way, that you iterates over collection only once. (as @Johnathan already offered to you in his answer)
bool[] results = await Task.WhenAll(tasks);
bool isTrueForAny = results.Any(b => b);
Awaiting Task.WhenAll unwraps the task results into an array, which you can test using Any().
Calling Any() directly on the IEnumerable will cause the iterator to be re run, which is why ProcessFile is being called again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With