微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

这个foreach的最干净的异步版本?

如何解决这个foreach的最干净的异步版本?

我在 AWS Lambda 中有一个方法可以接收完整的项目列表。它处理这些项目,然后将它们插入到 Dynamo 数据库表中。处理或插入数据库的顺序无关紧要。

我正在寻找最线程安全但易于理解的方式来加快运行速度;通过使用 async await 或其他(可能是并行的?)操作。

我在想 Parallel.ForEach() 但这似乎有点沉重。有没有更简单、更明显的方法

private async Task<int> LoadAutocomplete(IList<Item> resp)
{
    var client = new AmazonDynamoDBClient();

    foreach (var item in resp)
    {
        var request = new PutItemRequest
        {
            TableName = EnvironmentHelper.DynamoTableName,Item = new Dictionary<string,AttributeValue>()
            {
                { "LANGUAGE",new AttributeValue { S = item.LANGUAGE }},{ "COUNTRY",new AttributeValue { S = item.COUNTRY }}
            }
        };
        await client.PutItemAsync(request);

        System.Threading.Thread.Sleep(100);
    }
}

选项 1

private async Task<int> LoadAutocomplete(IList<Item> resp)
{
    var client = new AmazonDynamoDBClient();

    Parallel.ForEach(resp,async item =>
    {
        var request = new PutItemRequest
        {
            TableName = EnvironmentHelper.DynamoTableName,new AttributeValue { S = item.COUNTRY }}
            }
        };
        await client.PutItemAsync(request);
    }
}

选项 2 会导致编译器抱怨 LoadAutoComplete 方法“缺少 await 运算符并且将同步运行”。

选项 2 正如@jamesfaix 所建议的

private async Task<int> LoadAutocomplete(IList<Item> resp)
{
    var client = new AmazonDynamoDBClient();
    
    var tasks = items.Select(x => DoSomethingAsync(client,x)).ToList();
    
    await Task.WhenAll(tasks);
}

private DoSomething(AmazonDynamoDBClient client,Item item)
{
    var request = new PutItemRequest
    {
        TableName = EnvironmentHelper.DynamoTableName,AttributeValue>()
        {
            { "LANGUAGE",new AttributeValue { S = item.COUNTRY }}
        }
    };
    
    await client.PutItemAsync(request);
}

选项 + @martin 建议

帖子 "Use Parallel.For in batches in dotnet core" 确实回答了我的问题,但我选择了 @jamesfaix 发布的 the answer,因为它大大改进了我的代码

解决方法

以下是我首先要做的一些基本更改。您可能还可以从那里进行其他改进。

  1. 避免在异步代码中使用 Thread.SleepTask.Delay 是异步等效项。
  2. 在等待任何任务之前创建许多任务。如果可以,运行时将尝试同时运行一些。
private async Task<int> LoadAutocomplete2(IList<Item> resp)
{
    var client = new AmazonDynamoDBClient();

    var tasks = resp.Select(async item =>
    {
        var request = new PutItemRequest
        {
            TableName = EnvironmentHelper.DynamoTableName,Item = new Dictionary<string,AttributeValue>()
            {
                { "LANGUAGE",new AttributeValue { S = item.LANGUAGE }},{ "COUNTRY",new AttributeValue { S = item.COUNTRY }}
            }
        };

        var result = await client.PutItemAsync(request);
        await Task.Delay(100);
        return result;
    })
    .ToList(); // Make sure to materialize the IEnumerable!

    await Task.WhenAll(tasks);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。