Вызов асинхронной функции по таймеру в C#

422
29 июня 2017, 00:56

Можно ли как-нибудь вызвать по таймеру асинхронную функцию в C#? У обычного System.Threading.Timer callback-функция не может быть асинхронной, но, может, существуюут какие-нибудь другие способы?

Answer 1

С таймером и асинхронными методами надо быть аккуратнее. Как вы верно заметили, Timer не поддерживает асинхронные методы, а потому предложенный в другом ответе способ естественно имеет недостатки. TimerCallback -- это void-метод, т.е. по сути вы передаете async void метод. Отсюда два следствия:

  1. Таймер не будет дожидаться завершения функции, что может привести к нежелательным последствиям (например, вызовы будут накладываться друг на друга).

  2. Поскольку метод не ожидается, то и об исключениях в нем тоже никто не узнает. Обязательно нужно обрабатывать ошибки в самом методе, иначе исключение в пуле потоков может привести к завершению приложения (впрочем, этот пункт относится и к синхронным делегатам).

Встроенной поддержки регулярного запуска асинхронной функции в .NET пока нет. Самый простой вариант - написать метод с использованием бесконечного цикла и Task.Delay. Это по-настоящему асинхронный вариант периодического запуска асинхронного метода. Код может выглядеть так:

public async Task RunPeriodicallyAsync(
    Func<Task> func,
    TimeSpan interval,
    CancellationToken cancellationToken)
{
    while (!cancellationToken.IsCancellationRequested)
    {
        await Task.Delay(interval, cancellationToken)
        await func();
    }
}

Сюда по желанию/необходимости можно добавлять обработку ошибок, ConfigureAwait(false) и все, что еще понадобится.

Answer 2

В Timer можно передать асинхронный делегат, в коде выглядеть это будет так:

System.Threading.Timer timer = new Timer(async state =>
{
    await Task.Delay(500);
});
Answer 3

Я у себя в коде под Андроид сделал так:

    _timerUniversal = new Timer(CheckUniversal, _startTime, 0, TimerWait);
    async Task<int> CallAll()
    {
        await CheckNewUserCallback();
        await CheckNewGroupCallback();
        await CheckNewMessagesCallback();
        await WriteMessagesFromChannels();
        await AddChannelUsers();
        return 1;
    }
    void CheckUniversal(object state)
    {
        var rc = CallAll();
    }

Не знаю, насколько это правильно, но, вроде, работает.

READ ALSO
Разработка приложения для Android с C# [требует правки]

Разработка приложения для Android с C# [требует правки]

Читал, что есть Monodroid и Monotouch - фреймворки от XamarinИнформации маловато, оф

196
Оптимизация UI элементов

Оптимизация UI элементов

У меня есть View Model в которой содержится состояние объекта :

237
Как передать в NpgSqlCommand параметр из C#?

Как передать в NpgSqlCommand параметр из C#?

Как можно передать в скрипт параметр _data из c#:

316
Как поменять монитор в Unity во время игры?

Как поменять монитор в Unity во время игры?

Столкнулся с такой проблемой, что в Unity сложно поменять монитор, не нарушая работу других мониторов

354