我有一个 IEnumerable<Task>
,其中每个任务将调用相同的端点。但是,端点每秒只能处理这么多调用。 如何在每次调用之间设置半秒延迟?
我已经尝试添加 Task.Delay(),但当然等待它们只是意味着应用在一次发送所有调用之前等待半秒。
这是一个代码片段:
var resultTasks = orders
.Select(async task =>
{
var result = new VendorTaskResult();
try
{
result.Response = await result.CallVendorAsync();
}
catch(Exception ex)
{
result.Exception = ex;
}
return result;
} );
var results = Task.WhenAll(resultTasks);
我觉得我应该做这样的事情
Task.WhenAll(resultTasks.EmitOverTime(500));
...但我该怎么做呢?
最佳答案
换句话说,您在问题中描述的是 rate limiting .您希望对您的客户端应用速率限制策略,因为您使用的 API 在服务器上强制执行此类策略以保护自己免受滥用。
虽然您可以自己实现速率限制,但我建议您使用一些完善的解决方案。 Rate Limiter from Davis Desmaisons是我随机挑选的那个,我立刻喜欢上了它。它具有可靠的文档、出色的覆盖范围并且易于使用。它也可以作为 NuGet package 获得。 .
查看下面的简单代码段,它演示了按顺序运行半重叠任务,同时在前一个任务开始后将任务延迟半秒开始。每个任务至少持续 750 毫秒。
using ComposableAsync;
using RateLimiter;
using System;
using System.Threading.Tasks;
namespace RateLimiterTest
{
class Program
{
static void Main(string[] args)
{
Log("Starting tasks ...");
var constraint = TimeLimiter.GetFromMaxCountByInterval(1, TimeSpan.FromSeconds(0.5));
var tasks = new[]
{
DoWorkAsync("Task1", constraint),
DoWorkAsync("Task2", constraint),
DoWorkAsync("Task3", constraint),
DoWorkAsync("Task4", constraint)
};
Task.WaitAll(tasks);
Log("All tasks finished.");
Console.ReadLine();
}
static void Log(string message)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff ") + message);
}
static async Task DoWorkAsync(string name, IDispatcher constraint)
{
await constraint;
Log(name + " started");
await Task.Delay(750);
Log(name + " finished");
}
}
}
示例输出:
10:03:27.121 Starting tasks ...
10:03:27.154 Task1 started
10:03:27.658 Task2 started
10:03:27.911 Task1 finished
10:03:28.160 Task3 started
10:03:28.410 Task2 finished
10:03:28.680 Task4 started
10:03:28.913 Task3 finished
10:03:29.443 Task4 finished
10:03:29.443 All tasks finished.
如果您更改约束以允许每秒最多执行两个任务 (var constraint = TimeLimiter.GetFromMaxCountByInterval(2, TimeSpan.FromSeconds(1));
),这与每秒执行一个任务不同半秒,然后输出可能是这样的:
10:06:03.237 Starting tasks ...
10:06:03.264 Task1 started
10:06:03.268 Task2 started
10:06:04.026 Task2 finished
10:06:04.031 Task1 finished
10:06:04.275 Task3 started
10:06:04.276 Task4 started
10:06:05.032 Task4 finished
10:06:05.032 Task3 finished
10:06:05.033 All tasks finished.
请注意,当前版本的 Rate Limiter 以 .NETFramework 4.7.2+ 或 .NETStandard 2.0+ 为目标。
关于c# - 在调用之间暂停的多个异步调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56835195/