【发布时间】:2020-02-13 12:37:12
【问题描述】:
我需要尽可能快地并行运行许多任务。但是如果我的程序每 1 秒运行超过 30 个任务,就会被阻塞。如何确保每 1 秒间隔运行的任务不超过 30 个?
换句话说,如果在最后 1 秒的时间间隔内完成了 30 个任务,我们必须阻止新任务启动。
我丑陋的可能解决方案:
private async Task Process(List<Task> taskList, int maxIntervalCount, int timeIntervalSeconds)
{
var timeList = new List<DateTime>();
var sem = new Semaphore(maxIntervalCount, maxIntervalCount);
var tasksToRun = taskList.Select(async task =>
{
do
{
sem.WaitOne();
}
while (HasAllowance(timeList, maxIntervalCount, timeIntervalSeconds));
await task;
timeList.Add(DateTime.Now);
sem.Release();
});
await Task.WhenAll(tasksToRun);
}
private bool HasAllowance(List<DateTime> timeList, int maxIntervalCount, int timeIntervalSeconds)
{
return timeList.Count <= maxIntervalCount
|| DateTime.Now.Subtract(TimeSpan.FromSeconds(timeIntervalSeconds)) > timeList[timeList.Count - maxIntervalCount];
}
【问题讨论】:
-
实际的节流由 ReactiveX 操作符提供,例如
Window和Buffer。您可以使用具有有限 DOP 的ActionBlock<T>和可能的await Task.Delay()来确保您每秒拨打的电话不超过 N 次 -
谁投票关闭为“基于意见”,绝对不是。你可以争辩说过去也有类似的问题,但这绝对不是见仁见智的问题。
-
This is probably a duplicate。一个答案显示如何使用 DOP 为 50 的 DataFlow 块将并发操作限制为 50。另一个显示如何使用 SemaphoreSlim。可以使用 both - 一个 DOP 将操作限制为不超过 30(或更少),以及一个 SemaphoreSlim,每 1 秒由计时器重置一次。
-
假设您最初开始了 30 个任务。在时间 0:00.5(半秒后)所有 30 个任务仍在运行。此时 0:01.0(一秒后)有 15 个任务已完成,还有 15 个仍在运行。是否允许再开始 15 个任务?如果是,那么在 0:00.5 - 0:01.1 的时间间隔内,有超过 30 个任务处于活动状态。如果不是,则只有在完成所有 30 个初始任务后,您才能开始新任务。哪一个是期望的行为?
-
这是一个很好且足够详细的问题,为什么它被关闭了?
标签: c# .net asynchronous .net-core task-parallel-library