Я хочу реализовать специальный http-клиент, который будет накладывать ограничение на отправку запросов (например, запрос можно делать не чаще, чем раз в секунду). Я написал следующий код:
public class SmartClient
{
private readonly HttpClient _client;
private static DateTime? _lastRequest = null;
public SmartClient()
{
_client = new();
}
public async Task<string> Get(string url)
{
while (true)
{
if (_lastRequest != null && _lastRequest.Value.AddSeconds(1) > DateTime.Now)
{
await Task.Delay(100);
continue;
}
break;
}
_lastRequest = DateTime.Now;
Console.WriteLine($"Request: {url}");
var request = new HttpRequestMessage(HttpMethod.Get, url);
var response = await _client.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
}
Далее я инициализирую 10 объектов SmartClient, создаю на каждый по одной таске .Get() и помещаю все задачи в один список. Потом вызываю await Tasks.WaitAll(tasks); и жду, что все мои запросы выполнятся в течение 10 секунд. Но на практике получаю несколько одновременных запусков по несколько запросов за раз. Что я делаю не так?
_lastRequest, то мне казалось, что они отработают по очереди._lastRequest- статическое поле, общее для всех задач, так что какая разница сколько создается клиентов? – Scrzii Mar 09 '24 at 08:26_lastRequestи там, где этот самый_lastRequestобновляется. Результат тот же самый – Scrzii Mar 09 '24 at 08:50await Task.Delay(100)будет удерживать от семафор от релиза – vitidev Mar 09 '24 at 08:58HttpClientочень хорошо дополняется без всяких оберток/декораторов, делается это все при помощи простыхHandlerклассов. В документации есть отличный пример реализации "лимитера", который если немного дописать, получите нужный вам результат. А пока, как вам и сказали выше, у вас должен быть один экземпляр клиента и правильно созданные "Таски", чтоб все работало так, как вы ожидаете, а еще лучше семафор, а еще лучше очередь. – EvgeniyZ Mar 09 '24 at 10:56