c# - .Net Core 3.1 异步控制台应用程序在 VS 外部运行时挂起

标签 c# amazon-web-services asynchronous task

目标:对于 S3 URI 列表中的每个项目,获取对象数量。

我的 .Net Core 3.1 控制台应用程序在从 VS 2019 运行时运行良好,但一旦列表大小超过 5000 个项目左右,从 cmd(或任务计划程序、.bat 文件等)运行时就会出现问题。

事情看起来还不错,直到剩余任务减少到大约 500-1000 个。然后,大约 75% 的时间,剩余的任务似乎永远不会完成,应用程序永远挂起......尽管任务管理器中的 RAM 使用量减少到几乎为零。

我对异步相当陌生,我尝试根据我看到的无数解决方案重构一堆,但似乎无法弄清楚。

注意事项:

  • 在 VS 中,随着时间的推移,任务似乎恢复得更快,所以我的前 1000 个任务 任务可能需要 10 秒,下一个任务需要 9 秒,等等。在 VS 之外,似乎 相反,随着时间的推移,他们的恢复速度会变慢
  • 我在 AWS EC2(具有 32GB RAM 的 t3a.2xlarge)上运行此应用
  • 当我使用 PowerShell 运行它时,有时在运行过程中,它会断开我与 RDP 的连接,有时会多次断开连接。
  • 在 VS 中,应用程序使用了大约 75MB(带有一小部分 URI),大约 600MB(带有 150k 列表)。在 VS 之外,它使用大约 4 倍的 RAM。
  • 我尝试编译为 32 位和 64 位

代码:

namespace MyNamespace
{
    public class MyClass
    {
        private static DataTable dt;
        private static IAmazonS3 clientS3;

        static async Task Main(string[] args)
        {
            dt = <Call DB, get S3 URIs>;
            clientS3 = new AmazonS3Client();

            IEnumerable<Task<int>> callApiTasksQuery = from row in dt.AsEnumerable() select GetS3DataAsync(row);
            List<Task<int>> apiTasks = callApiTasksQuery.ToList();

            int total = 0;
            while (apiTasks.Any())
            {
                // if (apiTasks.Count % 100 == 0) await Console.Out.WriteLineAsync($"{apiTasks.Count} remaining.");
                Task<int> finishedTask = await Task.WhenAny(apiTasks);
                apiTasks.Remove(finishedTask);
                total += await finishedTask;
            }
        }
        
        static async Task<int> GetS3DataAsync(DataRow row)
        {
            var response = await clientS3.ListObjectsV2Async(new ListObjectsV2Request { BucketName = row[0], Prefix = row[1] });
            // Console.WriteLine(response.S3Objects.Count().ToString());  
            return 1;
        }
    }
}

最佳答案

我看到的唯一问题是在这段代码中,它的运行时间为 O(n^2):

int total = 0;
while (apiTasks.Any())
{
  // if (apiTasks.Count % 100 == 0) await Console.Out.WriteLineAsync($"{apiTasks.Count} remaining.");
  Task<int> finishedTask = await Task.WhenAny(apiTasks);
  apiTasks.Remove(finishedTask);
  total += await finishedTask;
}

如果不需要输出,则将其替换为单个 Task.WhenAll:

var totals = await Task.WhenAll(apiTasks);
var total = totals.Sum();

如果您确实需要输出,那么您可以通过完成一次重新排序,然后等待每个输出。有some blogs on how to do that ,或者您可以使用Nito.AsyncEx :

int total = 0;
var orderedApiTasks = apiTasks.OrderByCompletion();
for (int i = 0; i != orderedApiTasks.Count; ++i)
{
  total += await orderedApiTasks[i];
  if (i % 100 == 0) await Console.Out.WriteLineAsync($"{orderedApiTasks.Count - i} remaining.");
}

关于c# - .Net Core 3.1 异步控制台应用程序在 VS 外部运行时挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66910597/

相关文章:

macos - 创建 EC2 集群 : 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)

amazon-web-services - aws Elastic Beanstalk : cannot deploy to worker environment via eb cli

amazon-web-services - 模块化 aws lambda 代码的最佳实践

c# - 如何使 Dispose 等待所有异步方法?

javascript - 删除项目mongodb和 Node 异步

c# - 无法转换 viewModel 和 ObservableCollection

c# - ASP.NET MVC 3 - Linq to SQL 对象存储在 session 中

c# - 如何在 .NET 中启用程序集绑定(bind)失败日志记录 (Fusion)

angular - 在服务 http.get 调用完成后让组件执行函数

c# - 如何在asp.net中获取应用程序路径?