Dmi*_*nov 0 .net c# task-parallel-library async-await .net-4.5
我需要并行运行三个异步I / O操作,尤其是数据库调用。因此,我编写了以下代码:
// I need to know whether these tasks started running here
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
// await the results
var task1Result = await task1;
var task2Result = await task2;
var task3Result = await task3;
Run Code Online (Sandbox Code Playgroud)
这些GetThingOneAsync(), GetThingTwoAsync(), GetThingThreeAsync()方法彼此非常相似,只不过它们具有不同的返回类型(Task<string>, Task<int>, Task<IEnumerable<int>>)。下面是数据库调用之一的示例:
public async Task<IEnumerable<int>> GetThingOneAsync(string code)
{
return await db.DrType.Where(t => t.Code == code).Select(t => t.IdType).ToListAsync();
}
Run Code Online (Sandbox Code Playgroud)
在调试模式下,我可以看到var task1 = _repo.GetThingOneAsync();开始运行GetThingOneAsync()异步方法(与其他两个任务相同)。
我的同事说,_repo.GetThingOneAsync()这不会启动异步操作。他们说手术是在我们到达时开始的await(这句话对我来说似乎是错误的)。
因此,他们建议将我的代码修复为以下内容:
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
await Task.WhenAll(task1, task2, task3);
// then get the result of each task through `Result` property.
Run Code Online (Sandbox Code Playgroud)
在我看来,它与我在问题开始时写的内容相同,只是Task.WhenAll 在较早的任务出现故障时要等待以后的任务完成(这是Servy对这个问题的评论)
我知道我的问题有点重复,但是我想知道我做对还是错。
我的同事说_repo.GetThingOneAsync()不会启动异步操作。他们说手术是在我们到达等待状态时开始的(这对我来说似乎是错误的)。
他们错了。该方法在调用方法时开始。
通过启动具有一些可观察到的副作用(例如写入数据库)的操作,很容易证明这一点。调用方法,然后使用阻止应用程序Console.ReadKey()。然后,您将看到操作完成(在数据库中)而没有await。
剩下的问题全部与风格偏好有关。这些选项之间在语义上略有不同,但通常并不重要。
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
// await the results
var task1Result = await task1;
var task2Result = await task2;
var task3Result = await task3;
Run Code Online (Sandbox Code Playgroud)
上面的代码将await(异步等待)一次完成一项任务。如果所有三个都成功完成,则此代码等效于该Task.WhenAll方法。区别在于,如果task1或task2有异常,则task3永远不会等待。
这是我个人的最爱:
var task1 = _repo.GetThingOneAsync();
var task2 = _repo.GetThingTwoAsync();
var task3 = _repo.GetThingThreeAsync();
await Task.WhenAll(task1, task2, task3);
var task1Result = await task1;
var task2Result = await task2;
var task3Result = await task3;
Run Code Online (Sandbox Code Playgroud)
我喜欢Task.WhenAll它,因为它很明显。读取代码后,很明显它正在执行异步并发,因为那里是Task.WhenAll正确的。
我喜欢使用await代替,Result因为它对代码更改更具适应性。特别是,如果某个不喜欢的人Task.WhenAll出现并删除了它,那么您仍然会await执行这些任务而不是使用Result,这可能会导致死锁并在中包装异常AggregateException。Result之后起作用的唯一原因Task.WhenAll是因为这些任务已经完成,并且已经观察到它们的异常。
但这在很大程度上是意见。
| 归档时间: |
|
| 查看次数: |
118 次 |
| 最近记录: |