在同一行上使用await调用异步方法的目的是什么? (不是什么行为,但这种模式的实际用途是什么)。据我所知,这实际上是一个同步的“阻塞”调用,因为在此上下文中的执行在GetDocumentAsync完成之前不会继续,正确吗?
Document someDocument = await db.GetDocumentAsync(documentId);
//AFAIK blocks until GetdocumentAsync completes and returns
CalledAfterAwaitReturnsAndResultIsAvailable(someDocument.SomeProperty);
大多数教程展示了如何调用我见过的异步方法,并且我已经在其他代码中看到了它。对我而言,它违背了异步执行的目的。看起来好像从异步调用中受益,您可以在没有等待的情况下进行异步调用,并执行一些其他不相关的顺序工作(或启动其他异步调用),而不依赖于someDocument
,然后执行await
获取异步调用的结果,然后执行依赖于该返回的任何操作。这样,当异步调用也在另一个线程中工作时,可以执行其他不相关的处理。我已经看到了上述模式,我开始怀疑自己是否误解了一些东西。
以这种方式进行异步调用的实际应用是什么,这样它会一直阻塞直到它完成?
答案 0 :(得分:8)
await
关键字未在任务上调用Wait
,而是调用ContinueWith
。结果是,您获得完成回调而不是阻塞调用。
答案 1 :(得分:6)
我认为你缺少的关键是当你点击第一个await
时,你所在的函数返回Task<Document>
(假设你的函数被声明为public async Task<Document> Foo()
)并让打电话给你的人继续做其他工作。
然后调用者可以处理其他一些工作并稍后检查任务以查看它是否已完成,或者他可以立即自己await
并继续延期工作直到你找到有工作的人要做(在Forms或WPF上,它一直到消息泵,并让你在等待任务完成时继续响应。)
答案 2 :(得分:2)
这种模式的实际应用是当您想要将异步功能涓流/暴露给方法的其他潜在调用者时。在您的方法的上下文中,它将出现,就好像它是同步的,它实际上并不是阻塞的。父调用者可以从子方法异步功能中受益,并在GetDocumentAsync处理时执行并行处理。
public async Task<List<string>> ProcessDocument()
{
Document someDocument = await db.GetDocumentAsync(documentId);
//Since await is on the same line as the async call,
// Parse will not be called until GetDocumentAsync completes and result is available.
//Thus it appears to "block", it is not technically blocking,
// as a caller of ProcessDocument can start an async call to ProcessDocument
// and perform other parallel processing while GetDocumentAsync is processing,
// because ProcessDocument is marked async
return Parse(someDocument.Contents);
}
public async void ApplicationStart() {
//no await when calling async method, processing begins asynchrounously
Task<List<string>> parseDocTask = ProcessDocument();
//we will continue other work while ProcessDocument is asynchronously performing work
//We can execute DoIndependentWork while at the same time ProcessDocument is working on a separate thread asynchronously
DoIndependentWork();
//get result of async call, either will block until result is available,
// or if async ProcessDocument task has already completed, will continue immediately
List<string> parsedDocument = await parseDocTask;
//do something with parsedDocument
}
答案 3 :(得分:0)
该方法在逻辑上阻止。不同之处在于,如果异步代码是阻塞IO操作,则返回当前线程。
如果存在当前SynchronizationContext
,则会将续约发布到SynchronizationContext
(通常是UI消息泵);否则,继续将被发布到线程池。
这是对正在发生的事情的过度简化,但它有助于深入了解。