目标:对于 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/