.Net异步任务限制呼叫/秒

时间:2019-04-12 02:11:18

标签: c# .net asp.net-mvc asynchronous

因此,我刚刚被要求将我们正在调用的特定API的.Net异步代码的调用次数限制为5 /秒。

异步调用示例

var mylist = new List<Task<ApplicantDetails>>();

foreach (JToken result in results)
{
    mylist.Add(getCandidateResumeAsync(result));
}
await Task.WhenAll(mylist);

以及对getCandidateResumeAsync的API insode的实际调用

var candiateAttachmentsResponse = await Client.GetAsync(model["candidate"]["links"]["self"] + "/attachments");

我只需要每秒执行5次getCandidateResumeAsync函数。

关于我该如何处理的任何想法?

3 个答案:

答案 0 :(得分:3)

我将使用一个信号量来跟踪当前正在运行对该API的调用,然后在每次调用结束时释放一个。像这样:

public class Throttle
{
    private readonly TimeSpan perPeriod = TimeSpan.FromSeconds(1);
    private readonly SemaphoreSlim actionSemaphore = new SemaphoreSlim(5, 5);

    public async Task Queue(Func<Task> action, CancellationToken cancel)
    {
        await actionSemaphore.WaitAsync(cancel);
        try
        {
            await action();
        }
        finally
        {
            await Task.Delay(perPeriod, cancel).ContinueWith(_ => actionSemaphore.Release(1), cancel);
        }

    }
}

perPeriod将设置为1秒,而actionSemaphore将设置为5,这意味着它将允许一次运行5个请求。您会这​​样称呼它:

Throttle t = new Throttle();
t.Queue(SomeAction, CancellationToken.None);

然后您可以等待所有任务完成。

答案 1 :(得分:0)

在这种情况下,您可以限制并行任务,而不是限制每秒的任务。

  static async Task  Main(string[] args) {

      const ushort maxConcurrentTasks = 5;

      var resultBag = new ConcurrentBag<ApplicantDetails>();
      var queue = new ConcurrentQueue<JToken>(items);

      var tasks = Enumerable.Range(0, maxConcurrentTasks)
        .Select(_ => GetResultAsync(queue, resultBag));

      await Task.WhenAll(tasks);

      var result = resultBag.ToArray();
    }

    private static async Task GetResultAsync(ConcurrentQueue<JToken> queue, ConcurrentBag<ApplicantDetails> resultBag) {
      while (queue.TryDequeue(out var queueItem)) {
        var result = await getCandidateResumeAsync(queueItem);
        resultBag.Add(result);
      }
    }

我知道这并不是您要找的东西。但是也许您也可以接受这种方法。

答案 2 :(得分:0)

感谢所有的建议。

只需添加它,以防将来对其他人有帮助。

这是我想出的,它似乎运行正常。

        int counter = 0;
        foreach (JToken result in results)
        {
            counter++;
            if ((counter % 5) == 0) Task.Delay(1000);
            mylist.Add(getCandidateResumeAsync(result));
        }