Task.Any() 调用任务两次



>我正在运行如下任务。

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的原因。

相关内容

  • 没有找到相关文章

最新更新