Как я могу ждать минимальное количество времени? - PullRequest
0 голосов
/ 07 ноября 2018

У меня есть асинхронный метод C #, где я получаю ресурс HTTP, и я делаю это в бесконечном цикле. Однако я не хочу использовать ресурс слишком быстро. Мой текущий код:

HttpClient http = new HttpClient();
while (true) {
    // Long-poll the API
    var response = await http.GetAsync(buildUri());

    Console.WriteLine("Resp: " + response.ToString());
    Console.WriteLine("CONTENT:");
    Console.WriteLine(await response.Content.ReadAsStringAsync());
}

Однако я хочу убедиться, что я не делаю HTTP-запрос чаще, чем раз в 10 секунд. Поэтому я хочу запустить 10-секундный таймер в начале цикла, а в конце сказать: «дождаться завершения 10-секундного таймера». Есть ли способ сделать это в C # .NET?

Ответы [ 5 ]

0 голосов
/ 07 ноября 2018

Вы можете использовать CancellationTokenSource в сочетании с TaskCompletionSource, чтобы создать задачу «отсрочки», которая запускается при запуске вашего запроса и которую вы ожидаете, когда ваш запрос будет завершен:

private static Task GetDelayTask(TimeSpan delay, object state = null)
{
    var taskSource = new TaskCompletionSource<object>();
    var cts = new CancellationTokenSource(delay);
    cts.Token.Register(() =>
    {
        taskSource.SetResult(state);
        cts.Dispose();
    });
    return taskSource.Task;
}

Использование:

HttpClient http = new HttpClient();
while (true)
{
    var delayTask = GetDelayTask(TimeSpan.FromSeconds(10));
    // Long-poll the API
    var response = await http.GetAsync(buildUri());

    Console.WriteLine("Resp: " + response.ToString());
    Console.WriteLine("CONTENT:");
    Console.WriteLine(await response.Content.ReadAsStringAsync());
    await delayTask;
}
0 голосов
/ 07 ноября 2018

Вы можете использовать для этого простое StopWatch и Task.Delay для ожидания требуемого времени, если оно есть.

const int minimumTime = 10_000;
var sw = StopWatch.StartNew();

while (true) 
{
    // Long-poll the API
    var response = await http.GetAsync(buildUri());
    ...
    int difference = minimumTime - sw.EllapsedMiliseconds;

    if (difference > 0)
    {
        await Task.Delay(difference);
    }

    sw.Restart();
}

Это, однако, только для случая, когда вы хотите 10 секунд между каждым вызовом. Если для завершения API требуется 9 секунд, вы получите 2 вызова в секунду.
Если вы хотите всегда ждать 10 секунд, независимо от того, сколько времени понадобилось для завершения API, просто используйте:

const int waitTime = 10_000;

while (true) 
{
    // Long-poll the API
    var response = await http.GetAsync(buildUri());
    ...

    await Task.Delay(waitTime);
}
0 голосов
/ 07 ноября 2018

По простому:

while (true) {
    var rateLimit = Task.Delay(TimeSpan.FromSeconds(10));
    // ...await your http/whatever
    await rateLimit;
}

await rateLimit завершится немедленно, если работа http заняла 10 секунд.

Однако вы можете сравнить время до и после работы http, чтобы увидеть, нужно ли вам ждать; больше похоже:

while (true) {
    var timeBefore = ...
    // ...await your http/whatever
    var timeAfter = ...
    // ... calculate time left
    if (timeLeft > TimeSpan.Zero) await Task.Delay(timeLeft);
}

Это исключает необходимость использования сантехники для Task.Delay в сценариях, в которых она будет завершена немедленно.

0 голосов
/ 07 ноября 2018

Создайте StopWatch (и запустите его) при запуске цикла.

Затем, когда возвращается метод GetAsync, вы читаете ElapsedMilliseconds. Вычтите это значение из 10000. Теперь сделайте:

await Task.Delay(yourValue);

Теперь это занимает мин. 10 секунд для цикла.

код:

while (true) {
    // Long-poll the API

    StopWatch sw = StopWatch.StartNew();
    var response = await http.GetAsync(buildUri());

    Console.WriteLine("Resp: " + response.ToString());
    Console.WriteLine("CONTENT:");
    Console.WriteLine(await response.Content.ReadAsStringAsync());

    int milliseconds = 10000 - sw.ElapsedMilliSeconds;
    if (milliseconds > 0)
    {
        await Task.Delay(milliseconds);
    }
}
0 голосов
/ 07 ноября 2018

Не уверен, что это именно то, что вы ищете, но Task.Delay может приостановить цикл на заданные миллисекунды.

while (true)
{
 ... 
 await Task.Delay(10 * 1000);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...