Усыпление потока, ожидание, продолжение

242
26 марта 2018, 22:19

Выполняю множество последовательных get-запросов. Слать запросы можно не чаще, чем через 340 мс.
Каждый раз, когда поток доходит до get-запроса, нужно проверять, прошло ли 340 мс с последнего запроса. Если да, то делаем запрос, если нет - ждем и продолжаем.
Я сделал таймер, который запускается каждый раз после get-запроса, по истечении 340 мс выключается и делает запрос доступным с помощью bool переменной. Код:

static class RequestTimer
{
    public static bool requestIsAvailable;
    public static Timer requestTimer;
    static RequestTimer()
    {
        requestTimer = new Timer(340);
        requestTimer.Elapsed += OnTimedEvent;
        requestTimer.AutoReset = true;
        requestTimer.Enabled = false;
        requestIsAvailable = true;            
    }
    private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
    {
        requestIsAvailable = true;
        requestTimer.Enabled = false;
    }
}
public class VkRequest
{
    public string GetResponse(string url, string namesValues)
    {
        string result = null;
        for (bool inLoop = true; inLoop == true; )
        {
            if (!RequestTimer.requestIsAvailable) continue;
            RequestTimer.requestIsAvailable = false;
            using (var client = new WebClient())
            {
                client.Encoding = Encoding.UTF8;
                result = client.UploadString(url, namesValues);
                RequestTimer.requestTimer.Enabled = true;
            }
            inLoop = false;
        }
        return result;
    }
}

Понимаю, что решение мягко говоря не очень. Про ожидание зацикливанием я вообще молчу.
Читал про события, делегаты, async, await и т.д. Глаза разбегаются и нe могу понять, что конкретно лучше применять в моем случае.
Хотелось бы услышать какие-нибудь советы)

Answer 1

Если все запросы приходят в одном потоке, я бы сделал так:

Task cooldownTask = Task.CompletedTask;
Task currentRequest = null;
async Task<string> RequestAfterCooldown(string url, string namesValues)
{
    // дождаться окончания предыдущих заданий
    while (currentRequest != null)
        await currentRequest;
    // загеристрировать текущее задание
    TaskCompletionSource<bool> thisRequest = new TaskCompletionSource<bool>();
    currentRequest = thisRequest.Task;
    try
    {
        // выдержать сделать паузу
        await cooldownTask;
        // установить новую паузу для следующего запроса
        cooldownTask = Task.Delay(340);
        // сделать сам запрос и вернуть ответ асинхронно
        using (var client = new WebClient() { Encoding = Encoding.UTF8 })
            return await client.UploadStringTaskAsync(url, namesValues);
    }
    finally
    {
        // завершить текущий запрос для тех, кто дожидается его снаружи
        currentRequest = null;
        thisRequest.SetResult(true);
    }
}
READ ALSO
Переход между TextBox WPF

Переход между TextBox WPF

Есть два TextBox:

184
Отображение данных из буфера обмена

Отображение данных из буфера обмена

Необходимо написать программу для отображения данных из буфера обмена (для проверки сохранения объектов)

203
Google analytics дублирование

Google analytics дублирование

Проблема при отслеживании электронной торговли в google analytics, данные передаются через measurment protocolФормат запросов следующий: передача транзакции...

190
Не работает цикл в отдельном потоке WPF

Не работает цикл в отдельном потоке WPF

Программа запускается, но не выводит интерфейс

170