限制HttpClient请求速率的简单方法 [英] Simple way to rate limit HttpClient requests

查看:209
本文介绍了限制HttpClient请求速率的简单方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用System.Net.Http中的HTTPClient来针对API发出请求.该API每秒最多只能请求10个请求.

I am using the HTTPClient in System.Net.Http to make requests against an API. The API is limited to 10 requests per second.

我的代码大致如下:

    List<Task> tasks = new List<Task>();
    items..Select(i => tasks.Add(ProcessItem(i));

    try
    {
        await Task.WhenAll(taskList.ToArray());
    }
    catch (Exception ex)
    {
    }

ProcessItem方法可做一些事情,但始终使用以下方法调用API: await SendRequestAsync(..blah).看起来像这样:

The ProcessItem method does a few things but always calls the API using the following: await SendRequestAsync(..blah). Which looks like:

private async Task<Response> SendRequestAsync(HttpRequestMessage request, CancellationToken token)
{    
    token.ThrowIfCancellationRequested();
    var response = await HttpClient
        .SendAsync(request: request, cancellationToken: token).ConfigureAwait(continueOnCapturedContext: false);

    token.ThrowIfCancellationRequested();
    return await Response.BuildResponse(response);
}

本来代码可以正常工作,但是当我开始使用Task.WhenAll时,我开始从API获取超出速率限制"消息.如何限制提出请求的速度?

Originally the code worked fine but when I started using Task.WhenAll I started getting 'Rate Limit Exceeded' messages from the API. How can I limit the rate at which requests are made?

值得注意的是,根据项目的不同,ProcessItem可以进行1-4个API调用.

Its worth noting that ProcessItem can make between 1-4 API calls depending on the item.

推荐答案

API每秒最多只能请求10个请求.

The API is limited to 10 requests per second.

然后让您的代码执行10个批次的请求,确保它们至少花费一秒钟:

Then just have your code do a batch of 10 requests, ensuring they take at least one second:

Items[] items = ...;

int index = 0;
while (index < items.Length)
{
  var timer = Task.Delay(TimeSpan.FromSeconds(1.2)); // ".2" to make sure
  var tasks = items.Skip(index).Take(10).Select(i => ProcessItemsAsync(i));
  var tasksAndTimer = tasks.Concat(new[] { timer });
  await Task.WhenAll(tasksAndTimer);
  index += 10;
}

更新

我的ProcessItems方法根据项目进行1-4个API调用.

My ProcessItems method makes 1-4 API calls depending on the item.

在这种情况下,批处理不是合适的解决方案.您需要将异步方法限制为某个特定的 number ,即SemaphoreSlim.棘手的部分是您想允许随着时间的流逝.

In this case, batching is not an appropriate solution. You need to limit an asynchronous method to a certain number, which implies a SemaphoreSlim. The tricky part is that you want to allow more calls over time.

我还没有尝试过这段代码,但是我要遵循的总体思路是具有一个周期性函数,该函数可以将信号量最多释放 10次.所以,像这样:

I haven't tried this code, but the general idea I would go with is to have a periodic function that releases the semaphore up to 10 times. So, something like this:

private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(10);

private async Task<Response> ThrottledSendRequestAsync(HttpRequestMessage request, CancellationToken token)
{
  await _semaphore.WaitAsync(token);
  return await SendRequestAsync(request, token);
}

private async Task PeriodicallyReleaseAsync(Task stop)
{
  while (true)
  {
    var timer = Task.Delay(TimeSpan.FromSeconds(1.2));

    if (await Task.WhenAny(timer, stop) == stop)
      return;

    // Release the semaphore at most 10 times.
    for (int i = 0; i != 10; ++i)
    {
      try
      {
        _semaphore.Release();
      }
      catch (SemaphoreFullException)
      {
        break;
      }
    }
  }
}

用法:

// Start the periodic task, with a signal that we can use to stop it.
var stop = new TaskCompletionSource<object>();
var periodicTask = PeriodicallyReleaseAsync(stop.Task);

// Wait for all item processing.
await Task.WhenAll(taskList);

// Stop the periodic task.
stop.SetResult(null);
await periodicTask;

这篇关于限制HttpClient请求速率的简单方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆