虽然我可以使我的大部分方法异步,但我觉得我对何时必须这样做没有基本的了解。
从最低级别开始。听起来您已经开始了,但如果您在最低级别寻找更多内容,那么经验法则是应该制作任何基于 I/O 的内容async
(e.g., HttpClient
).
然后就是重复的问题async
感染。您想使用异步方法,因此您可以使用await
。所以该方法必须是async
。所以它的所有调用者都必须使用await
,所以它们也必须是async
, etc.
如果我构建了一个消息循环,我想要对并行度进行一些控制,那么我将如何调用程序的第一个异步方法?
让框架来负责这件事是最简单的。例如,您可以只返回Task<T>
来自 WebAPI 操作,并且框架理解这一点。类似地,UI 应用程序也有一个内置的消息循环async
会自然而然地配合。
如果遇到框架不理解的情况Task
或者有一个内置的消息循环(通常是控制台应用程序或 Win32 服务),您可以使用AsyncContext输入我的AsyncEx library http://nitoasyncex.codeplex.com/wikipage?title=AsyncContext. AsyncContext
只需安装一个“主循环”(与async
) 到当前线程。
由于 HttpClient 没有任何同步方法,如果我有一个不支持异步的抽象,我可以安全地假设做什么?
正确的做法是改变抽象。不要尝试阻塞异步代码;我描述的是常见的死锁场景 http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html详细在我的博客上。
你可以通过创建来改变抽象async
-友好的。例如,改变IUserContext IUserContextService.GetUserContext()
to Task<IUserContext> IUserContextService.GetUserContextAsync()
.
我读过有关ConfigureAwait(false) 的内容,但我不太明白它的作用。对我来说很奇怪的是它是在异步调用之后设置的。
你可能会发现我的async intro http://blog.stephencleary.com/2012/02/async-and-await.html有帮助。我不会多说ConfigureAwait
在这个答案中,因为我认为它并不直接适用于这个问题的一个好的解决方案(但我并不是说它不好;它实际上should除非你使用can't用它)。
请记住async
是一个具有优先规则的运算符等等。一开始感觉很神奇,但实际上并没有那么神奇。这段代码:
var result = await httpClient.GetAsync(url).ConfigureAwait(false);
与此代码完全相同:
var asyncOperation = httpClient.GetAsync(url).ConfigureAwait(false);
var result = await asyncOperation;
通常没有竞争条件async
代码是因为 - 即使该方法是异步- 也是顺序的。该方法可以暂停在await
,并且在此之前不会恢复await
完成。
当您有一个允许并行发生的消息循环并且您有异步方法时,就有机会最大限度地减少延迟。
这是您第二次提到“并行”“消息循环”,但我认为您真正想要的是让多个(异步)消费者在同一个队列中工作,对吗?这很容易做到async
(请注意,在此示例中,单个线程上只有一个消息循环;当一切都是异步时,这通常就是您所需要的):
await tasks.WhenAll(ConsumerAsync(), ConsumerAsync(), ConsumerAsync());
async Task ConsumerAsync()
{
for (;;) // TODO: consider a CancellationToken for orderly shutdown
{
var m = await mq.ReceiveAsync();
var c = GetCommand(m);
await c.InvokeAsync();
m.Delete();
}
}
// Extension method
public static Task<Message> ReceiveAsync(this MessageQueue mq)
{
return Task<Message>.Factory.FromAsync(mq.BeginReceive, mq.EndReceive, null);
}
您可能还会感兴趣TPL数据流 http://msdn.microsoft.com/en-us/library/hh228603%28v=vs.110%29.aspx。 Dataflow 是一个能够理解并能够很好地工作的库async
代码,并且内置了很好的并行选项。