C#异步等待使用LINQ ForEach() [英] C# async await using LINQ ForEach()

查看:409
本文介绍了C#异步等待使用LINQ ForEach()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码正确使用了异步/等待模式.

I have the following code that correctly uses async/await paradigm.

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);
    }
}

如果我要使用LINQ ForEach()而不是使用foreach(),则等效的编写方式是什么?例如,此代码会产生编译错误.

What is the equivalent way to write this if, instead of using foreach(), I want to use LINQ ForEach()? This one, for example, gives compile error.

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);
        });
}

我唯一没有编译错误的代码就是这个.

The only code I got to work without compile error is this.

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);
        });
}

我担心此方法没有异步签名,只有正文有. 这与我上面的第一段代码正确吗?

I'm worried that this method has no async signature, only the body does. Is this the correct equivalent of my first block of code above?

推荐答案

否.不是.此ForEach不支持async-await,并且要求您的lambda为async void,应用于事件处理程序.使用它可以同时运行所有async操作,而不必等待它们完成.

No. It isn't. This ForEach doesn't support async-await and requires your lambda to be async void which should only be used for event handlers. Using it will run all your async operations concurrently and won't wait for them to complete.

您可以像使用常规foreach一样使用,但是如果需要扩展方法,则需要特殊的async版本.

You can use a regular foreach as you did but if you want an extension method you need a special async version.

您可以自己创建一个遍历项目,执行async操作并await s的人:

You can create one yourself that iterates over the items, executes an async operation and awaits it:

public async Task ForEachAsync<T>(this IEnumerable<T> enumerable, Func<T, Task> action)
{
    foreach (var item in enumerable)
    {
        await action(item);
    }
}

用法:

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);
    });
}

ForEachAsync的另一种(通常更有效)的实现方式是先启动所有async操作,然后再将所有await操作一起启动,但这只有在您的操作可以同时运行而又不能同时运行时才有可能总是这样(例如实体框架):

A different (and usually more efficient) implementation of ForEachAsync would be to start all the async operations and only then await all of them together but that's only possible if your actions can run concurrently which isn't always the case (e.g. Entity Framework):

public Task ForEachAsync<T>(this IEnumerable<T> enumerable, Func<T, Task> action)
{
    return Task.WhenAll(enumerable.Select(item => action(item)));
}


正如注释中所指出的那样,您可能不希望在一开始的foreach中使用SaveChangesAsync.准备更改,然后一次保存所有更改,可能会更有效率.


As was noted in the comments you probably don't want to use SaveChangesAsync in a foreach to begin with. Preparing your changes and then saving them all at once will probably be more efficient.

这篇关于C#异步等待使用LINQ ForEach()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆