>我正在运行如下任务。
var tasks = from job in jobs select ProcessFile(job);
其中进程文件是一个返回布尔任务的方法
private async Task<bool> ProcessFile(Job job)
现在奇怪的是,我想检查任何任务结果是否真实,如下所示。
await Task.WhenAll(tasks);
var isTrueForAny =tasks.Any(x => x.Result == true);
但是在这一点上,我的方法 ProcessFile(job( 再次被调用,尽管我只有一个作业。你们能帮我了解原因是什么吗?
这种行为的原因是延迟执行。
延迟执行意味着表达式的计算是 延迟到实际需要其实现值。
让我们一步一步地看一下:
var tasks = from job in jobs select ProcessFile(job);
将tasks
变量的值视为 sql 查询。每次当您尝试在需要该查询值的地方使用变量时tasks
都会执行它。
第一次在等待该任务时执行"查询"。
await Task.WhenAll(tasks);
第二次,当您迭代该query
的结果时。但是,并非所有任务都会执行两次,因为Any
一旦找到第一个匹配的任务就会停止迭代。
var isTrueForAny =tasks.Any(x => x.Result == true);
看看 LINQ 中的Deferred Execution
概念。
为了解决问题,您需要强制立即执行。若要强制立即执行不生成单一实例值的查询,可以对查询或查询变量调用ToList
方法、ToDictionary
方法或ToArray
方法。但是,当您从集合中投影Task
对象时,这将是有问题的。您可以通过创建扩展方法ToListAsync
来解决此问题。
或者为了解决这个问题,你只需要以某种方式更改你的代码,你只迭代一次集合。(正如@Johnathan在他的回答中已经提供给你的(
bool[] results = await Task.WhenAll(tasks);
bool isTrueForAny = results.Any(b => b);
等待Task.WhenAll
将任务结果解包到一个数组中,您可以使用Any()
进行测试。
直接在IEnumerable
上调用Any()
将导致迭代器重新运行,这就是再次调用ProcessFile
的原因。