Хорошо ли использовать async void для запуска задачи, не связанной с процессором, после определенной задержки? - PullRequest
0 голосов
/ 02 апреля 2019

Вот мой код:

class StateManager
{
    private readonly ConcurrentDictionary<int, bool> _states = new ConcurrentDictionary<int, bool>();

    public void SetState(int id, bool state)
    {
        _states[id] = state;

        if (!state)
            RemoveLately(id);
    }

    private async void RemoveLately(int id)
    {
        await Task.Delay(10000).ConfigureAwait(false);
        _states.TryRemove(id, out _);

    }
}

Моя цель - убрать предмет по прошествии определенного времени. Я не хочу использовать Task.Run для RemoveLately, так как его можно вызывать тысячи раз. Какие могут быть недостатки такой практики, если таковые имеются?

Ответы [ 2 ]

3 голосов
/ 02 апреля 2019

Моя цель - удалить элемент по прошествии определенного времени.

Тогда почему бы не использовать кеш?

Хорошо ли это использоватьasync void?

Указание для async void состоит в том, чтобы избегать async void, если вы не реализуете обработчик событий (или что-то, что логически похоже на обработчик событий) .Таким образом, реальный вопрос здесь таков: является ли RemoveLately логически «обработчиком событий»?Я вижу аргумент, где его можно считать одним;в частности, TryRemove вызывается в ответ на «событие» таймера (Task.Delay).Поэтому я бы не сказал, что async void здесь не так, но у него есть недостатки.

Какие могут быть недостатки такой практики, если таковые имеются?

Существует одна основная проблема с async void методами: другой код не может знать, когда этот метод завершен.

Эта основная проблема проявляется несколькими способами:

  • Ваш код не может перехватитьили обработать исключения из RemoveLately.Поскольку нет способа наблюдать завершение для async void методов, также нет способа наблюдать исключения.Таким образом, async void методы просто вызывают любые исключения непосредственно в их исходном SynchronizationContext.В большинстве случаев это означает, что исключения в методах async void приводят к сбою приложения. Методы
  • async void сложно протестировать.Это связано с тем, что код модульного тестирования не может знать, когда завершился метод async void.
  • Ваш код не может знать, когда безопасно завершить работу (где область действия «выключить» может означать «выход из программы»).", или" распоряжаться StateManager ", или что-нибудь промежуточное).Это связано с тем, что ваш код не может знать, может ли async void еще работать.В этом конкретном случае, когда RemoveLately просто удаляет объект из кэша, это нормально игнорировать, но в общем случае async void означает, что приложение никогда не знает, когда оно «выполнено».
0 голосов
/ 02 апреля 2019

Нет асинхронной пустоты (почти) всегда плохо (с. это ). Как заявил Стивен в своей статье и своем ответе здесь, есть несколько причин иметь асинхронные void-методы (а именно асинхронные обработчики событий, которые никогда не имеют никакого другого «возвращаемого» значения, кроме void). Причины, по которым вам следует перейти на асинхронную задачу, и почему они лучше, объясняет Стивен в своем ответе.

Вот почему я бы предложил, чтобы ваш метод выглядел так:

private async Task RemoveLately(int id)
    {
        await Task.Delay(10000).ConfigureAwait(false);
        _states.TryRemove(id, out _);

    }

В качестве небольшого замечания (если можно): Если вы не знаете, что выбрать и / или можете выбрать Task (или Task<T>) или async void, попробуйте использовать Task, потому что почти в каждом случае (кроме обработки событий) вам лучше с Task, чем с async void.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...