【发布时间】:2021-04-01 19:39:26
【问题描述】:
目标:对于 S3 URI 列表中的每个项目,获取对象数。
当从 VS 2019 运行时,我的 .Net Core 3.1 控制台应用程序运行良好,但一旦列表大小超过 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 之外,它使用大约 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;
}
}
}
【问题讨论】:
-
为什么选择 DoMainAsync?为什么不直接把那里的逻辑放到Main里面,标记为
async,然后去掉多余的方法呢? -
“它没有影响” - 你的意思是除了让你的代码更干净?这绝对是你应该做的。我与 AWS 合作的次数不多,但您似乎向 API 发出了大量请求。我希望这会受到严重的 I/O 限制,所以你真的不应该一次做超过几个。该 API 允许您访问它的频率可能存在速率限制。
-
同意,听起来你想限制并发请求的数量,如下所述:stackoverflow.com/questions/10806951/…
-
在 VS 代码中运行实际上可能会减慢它的速度(由于网络延迟),以至于它没有遇到速率限制。从 EC2 实例调用它可能会更快地进行调用,从而达到速率限制。你在本地运行代码但在 VS Code 中没有同样的问题吗?
-
您是否尝试过从 Visual Studio 运行它,但没有附加调试器? (Ctrl+F5)
标签: c# amazon-web-services asynchronous task