C# 如何在不等待的情况下等待异步操作的结果?

C# 如何在不等待的情况下等待异步操作的结果?,c#,async-await,C#,Async Await,如果我将public async void A()标记为async,我将在try catch中调用A(),我永远不会在catch中。首先,您需要一个表示所有操作的任务。最简单的方法是使用一点LINQ: void A() { var tasks = new List<Task<BulkWriteResult<JobInfoRecord>>>(); foreach (var document in documents) { var task = rec

如果我将
public async void A()
标记为
async,我将在
try catch
中调用
A()
,我永远不会在
catch

中。首先,您需要一个表示所有操作的
任务。最简单的方法是使用一点LINQ:

void A()
{
var tasks = new List<Task<BulkWriteResult<JobInfoRecord>>>();

foreach (var document in documents)
{
     var task = records.BulkWriteAsync(operationList, writeOptions);
     tasks.Add(task);
}

Task.WaitAll(tasks.ToArray());
}
然后,理想情况下,您希望等待该任务。如果不可能,你可以试试

Task.WhenAll(documents.Select(i => records.BulkWriteAsync(...)));
但是,请确保所有任务都没有线程关联性——这是获得死锁的好方法。当任务本身需要UI线程时,在UI线程上等待任务就是一个典型的例子

await
的全部要点是,它允许您像处理同步代码一样处理异步代码。因此,从外部看,似乎您从未离开过该方法,直到您实际得到一个
返回值
(或方法的结尾)。但是,要使其工作,您的方法必须返回
任务
(或
任务
),被调用方必须
依次等待
您的方法

这样的代码:

task.GetAwaiter().GetResult();
将显示为完全同步运行,所有异常都将照常处理(尽管我们使用的是
任务。当所有
时,一些异常将被包装在
聚合异常中


然而,这实际上不可能用.NET和C#的构建方式来处理,因此C#编译器欺骗-
wait
基本上是一个
返回
,它向您保证将来会得到的结果。当这种情况发生时,控件返回到上次
wait
离开的位置<代码>任务
就是这个承诺-如果使用
异步void
,被调用方将无法知道发生了什么,并且它没有选择,只能继续,就好像异步方法是一个run-and-forget方法一样。如果使用
async Task
,则可以
等待
异步方法,然后一切都会再次“感觉”同步。不要打破链条,这样的错觉是完美的:)

所以你只想等待最后一次手术的结果还是什么?为什么不让
A
async
?异步调用链应该尽可能地异步。下次你应该清楚地表达你想在问题中实现什么。这就是为什么发布一个方法总是一个好主意。您仍然没有说为什么使方法
async
不适合您。在处理异步代码时,它实际上应该是默认值。这只是意味着在某个时候,您打破了
wait
链,而没有正确处理孤立的
任务。你为什么这么做?您正在使用
异步void
方法吗?不要。如果您不需要返回任何数据,只需使用
async Task
即可。我添加了更多信息。调用
Result
Wait
GetResult
从来都不是明智之举。如果你需要它,你的设计是错误的。@Gusdor有时这不是你的选择。可能您被一个不支持异步方法的框架调用。同步等待可以工作,只要您确保避免同步问题(与任何多线程代码一样)。当然,这是不可取的,但有时你就是别无选择。@ivan_petrushenko如果你不能使用
wait
,那就可以了。然而,
GetAwaiter().GetResult()
将为您提供更多有意义的堆栈跟踪—它假装一切都是一个同步的方法调用链
Wait
不存在,因此您可能会获得与
GetResult
相同的堆栈跟踪,但它也可能根本不会提供可用的堆栈跟踪。
task.GetAwaiter().GetResult();
try
{
  tasks = Task.WhenAll(documents.Select(i => ...));

  await tasks;
}
catch (Exception ex)
{
  // Handle the exception
}