Sam*_*evx 15 .net c# linq async-await
我有以下代码正确使用async/await范例.
internal static async Task AddReferencseData(ConfigurationDbContext context)
{
foreach (var sinkName in RequiredSinkTypeList)
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
}
}
Run Code Online (Sandbox Code Playgroud)
如果不是使用foreach(),我想使用LINQ ForEach(),那么写这个的等效方法是什么?例如,这个给出了编译错误.
internal static async Task AddReferenceData(ConfigurationDbContext context)
{
RequiredSinkTypeList.ForEach(
sinkName =>
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
});
}
Run Code Online (Sandbox Code Playgroud)
我没有编译错误的唯一代码就是这个.
internal static void AddReferenceData(ConfigurationDbContext context)
{
RequiredSinkTypeList.ForEach(
async sinkName =>
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
});
}
Run Code Online (Sandbox Code Playgroud)
我担心这种方法没有异步签名,只有正文.这是我上面第一段代码的正确等价吗?
i3a*_*non 19
不,不是.这ForEach不支持async-await并且要求您的lambda async void应该只用于事件处理程序.使用它将async同时运行所有操作,不会等待它们完成.
您可以使用常规方法foreach,但如果您需要扩展方法,则需要特殊async版本.
您可以自己创建一个迭代项目,执行async操作并执行操作await:
public async Task ForEachAsync<T>(this IEnumerable<T> enumerable, Func<T, Task> action)
{
foreach (var item in enumerable)
{
await action(item);
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
internal static async Task AddReferencseData(ConfigurationDbContext context)
{
await RequiredSinkTypeList.ForEachAsync(async sinkName =>
{
var sinkType = new SinkType() { Name = sinkName };
context.SinkTypeCollection.Add(sinkType);
await context.SaveChangesAsync().ConfigureAwait(false);
});
}
Run Code Online (Sandbox Code Playgroud)
一个不同的(通常是更有效的)实现ForEachAsync将是启动所有async操作,然后才将await所有操作一起启动,但这只有在您的操作可以并发运行时才有可能(并非总是如此)(例如,实体框架):
public Task ForEachAsync<T>(this IEnumerable<T> enumerable, Func<T, Task> action)
{
return Task.WhenAll(enumerable.Select(item => action(item)));
}
Run Code Online (Sandbox Code Playgroud)
正如评论中所指出的那样,您可能不希望SaveChangesAsync在foreach中使用它.准备更改然后立即保存所有更改可能会更有效.
初始示例foreach在每次循环迭代后有效等待。最后一个示例调用List<T>.ForEach()的Action<T>含义是,您的异步 lambda 将编译为void委托,而不是标准Task.
实际上,该ForEach()方法将一次又一次地调用“迭代”,而无需等待每一次完成。这也将传播到您的方法,这意味着该方法AddReferenceData()可能会在工作完成之前完成。
所以不,它不是等价的,并且行为完全不同。事实上,假设它是一个 EF 上下文,它将会崩溃,因为它可能无法在多个线程中同时使用。
另请阅读Deepu 提到的http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx ,了解为什么最好坚持使用foreach.
| 归档时间: |
|
| 查看次数: |
14196 次 |
| 最近记录: |