【发布时间】:2015-08-18 13:41:04
【问题描述】:
我有以下(简化的)代码:
public async Task GetData(DomainObject domainObject, int depth)
{
// This async operation is really quick, and there's usually like five.
IEnumerable<TierOne> tierOnes = await domainObject.GetTierOnesAsync();
var tierOneTasks = tierOnes.Select(async tierOne =>
{
// This async operation is really quick and there's usually like three.
IEnumerable<TierTwo> tierTwos = await tierOne.GetTierTwosAsync();
if (depth <= TierTwoDepth)
return;
var tierTwoTasks = tierTwos.Select(async tierTwo =>
{
// This async operation is usually fast, and there's usually >= 100.
IEnumerable<TierThree> tierThrees = await tierTwo.GetTierThreesAsync();
if (depth <= TierThreeDepth)
return;
var tierThreeTasks = tierThrees.Select(async tierThree =>
{
// This async operation is SLOW, and there's usually.. 50?
await tierThree.GetTierFoursAsync();
});
await Task.WhenAll(tierThreeTasks.ToArray());
});
await Task.WhenAll(tierTwoTasks.ToArray());
});
await Task.WhenAll(tierOneTasks.ToArray());
}
根据我所看到的,它的扩展性似乎不是很好。所有Async 操作都是“真正的异步”操作,这意味着它们都是 I/O。
我是否在这种情况下错误地使用了 Async/Await?根据我目前的观察,它没有达到我的预期。 TPL DataFlow 会是我的解决方案吗?
【问题讨论】:
-
“它似乎扩展得很好”是一个错字,你想把
not放在那里吗?如果是这样,以何种方式扩展,您希望它完成得更快还是不会给系统带来那么多负载?您如何测试缩放比例? -
您使用了很多
IEnumerables作为异步返回值。您确定延迟执行不会干扰您假设的并行化吗? -
异步并没有让它更快,事实上,由于开销,它通常比相同代码的同步版本慢一点,它为你做的是在你开始之前允许更高的负载以获得性能下降。
-
@Cameron:由于您的方法都在执行 I/O(可能针对同一台服务器),请仔细检查您的
ServicePointManager.DefaultConnectionLimit设置。或者只是在启动时将其设置为int.MaxValue,看看问题是否仍然存在。 -
客户端(浏览器、应用程序等)不应该向同一个域发出超过两个 HTTP 请求的非官方标准缺乏。一个更好的实现方式是使用具有例如 10 个并发任务的 ActionBlock,这样您就可以控制并发请求的数量,即使您有 100 个 URL 可以访问。更好的是,您可以在每层有一个具有不同 DOP 设置的块,将它们的结果提供给下一层
标签: c# asynchronous async-await tpl-dataflow