程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了.Net Core 3.1 异步控制台应用程序在 VS 之外运行时挂起大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决.Net Core 3.1 异步控制台应用程序在 VS 之外运行时挂起?

开发过程中遇到.Net Core 3.1 异步控制台应用程序在 VS 之外运行时挂起的问题如何解决?下面主要结合日常开发的经验,给出你关于.Net Core 3.1 异步控制台应用程序在 VS 之外运行时挂起的解决方法建议,希望对你解决.Net Core 3.1 异步控制台应用程序在 VS 之外运行时挂起有所启发或帮助;

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

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

在剩下大约 500-1000 个任务之前,一切似乎都很好。然后,大约 75% 的时间,剩余的任务似乎永远不会完成,应用程序永远挂起......尽管 RAM 使用量在任务管理器中减少到几乎为零。

我对 Async 还很陌生,我已经尝试根据我看到的无数解决方案重构一堆,但似乎无法弄清楚。

注意事项:

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

代码:

@H_772_26@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 @R_283_10586@l = 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); @R_283_10586@l += 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) 时间内运行:

@H_772_26@int @R_283_10586@l = 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); @R_283_10586@l += await finishedTask; }

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

@H_772_26@var @R_283_10586@ls = await Task.WhenAll(apiTasks); var @R_283_10586@l = @R_283_10586@ls.sum();

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

@H_772_26@int @R_283_10586@l = 0; var orderedApiTasks = apiTasks.OrderByCompletion(); for (int i = 0; i != orderedApiTasks.Count; ++i) { @R_283_10586@l += await orderedApiTasks[i]; if (i % 100 == 0) await Console.out.WriteLineAsync($"{orderedApiTasks.Count - i} remaining."); } ,

以下批处理解决方案有效。它在 2-3 秒内恢复每个批次(如果在调试器中运行约 10 秒)

感谢 https://www.michalbialecki.com/2018/04/19/how-to-send-many-requests-in-parallel-in-asp-net-core/ 并感谢所有人的帮助!

@H_772_26@using System; using System.Threading.Tasks; using System.Collections.Generic; using System.Data; using Amazon.S3; using System.Linq; using Amazon.S3.Model; namespace MyNamespace { public class S3PrefixGrabber { private static IAmazonS3 clientS3; static async Task Main(String[] args) { var query = "SELECT bucket,prefix from myTable"; DataTable dt = GetstuffFromDB(query); List<S3Prefix> unpopulatedList = (from DataRow dr in dt.Rows SELEct new S3Prefix() { B = dr[0].ToString(),P = dr[1].ToString() }).ToList(); var batchSize = 1000; int numberOfBatches = (int)R_358_11845@ath.Ceiling((doublE)unpopulatedList.Count() / batchSizE); List<S3Prefix> populatedList = new List<S3Prefix>(); for (int i = 0; i < @R_674_10793@erOfBatches; i++) { var currentItems = unpopulatedList.Skip(i * batchSizE).Take(batchSizE); var tasks = currentItems.SELEct(id => GetS3DataAsync(id)); populatedList.AddRange(await Task.WhenAll(tasks)); } } static async Task<S3Prefix> GetS3DataAsync(S3Prefix s3Item) { clientS3 = new AmazonS3Client(); var response = await clientS3.ListObjectsV2Async(new ListObjectsV2request { BucketName = s3Item.b,Prefix = s3Item.P }); s3Item.O = response.S3Objects.Count; return s3Item; } } public class S3Prefix { public String B { get; set; } public String P { get; set; } public int O { get; set; } } }

运行 10k 条记录,RAM 为 75MB,CPU 为 40%
运行 300k 条记录,RAM 为 700MB,CPU 为 40%

日志中的一个片段(我没有包含在上面的代码中),仅供参

06:32:52.310: ================== 开始 ==================
06:32:52.795:查询:SELECT 存储桶,前缀 FROM myTable
06:32:52.874:打开连接
06:32:54.205:灌装适配器
06:33:06.309: 313863 行从 DB
返回 06:33:07.647:批处理...批处理大小:1000 批处理:314
06:33:07.647:开始第 1/314 批……在 02.84 秒内完成。
06:33:10.492:开始第 2/314 批次......在 02.48 秒内完成。
06:33:12.977:开始第 3/314 批次......在 02.19 秒内完成。
...
06:38:55.435:开始批次 150/314... 02.32 秒内完成。
06:38:57.761:开始批次 151/314... 02.17 秒内完成。
06:38:59.936:开始批次 152/314... 02.27 秒内完成。
...
06:45:13.579:开始批次 312/314... 02.17 秒内完成。
06:45:15.751:开始批次 313/314... 02.35 秒内完成。
06:45:18.105:开始批次 314/314... 02.10s 完成。
06:45:20.211:将 313863 行写入 CSV...完成。
06:45:23.086:DB 行:313863 CSV 行:313863 NoTinS3:0 InS3ButNotFound:0
06:45:23.087:在 12:30.77 秒内完成。
06:45:23.092:==================结束==================

大佬总结

以上是大佬教程为你收集整理的.Net Core 3.1 异步控制台应用程序在 VS 之外运行时挂起全部内容,希望文章能够帮你解决.Net Core 3.1 异步控制台应用程序在 VS 之外运行时挂起所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签:3.1Core