2016-08-17 3 views
2

Я разрабатываю приложение для мониторинга определенных задач (например, если некоторые службы/веб-сайты в настоящее время работают и работают, некоторые записи в базе данных существуют и т. Д.). И поскольку большинство этих задач длится долго, я использую TPL с async/await.Замена для async void

У меня есть базовый класс для всех таких задач:

public abstract class LongRunningOperation 
{ 
    // .. some props... 

    internal async void Start() 
    { 
     try 
     { 
      this.Status = OperationStatus.Started; 
      await this.DoStart(); 
      this.Status = OperationStatus.Finished; 
     } 
     catch (Exception e) 
     { 
      this.Status = OperationStatus.Error; 
      this.Message = e.ToString(); 
     } 
    } 

    protected abstract Task DoStart(); 
} 

И метод, который запускает эти задачи выглядят следующим образом:

public static LongRunningOperation[] LaunchOperations() 
{ 
    LongRunningOperation[] operations = GetAllLongRunningOperations(); 
    foreach (var o in operations) 
     Task.Factory.StartNew(() => { o.Start(); }); 
    return operations; 
} 

Массив, возвращаемый этот метод используется для мониторинга всех LongRunningOperation s и запишите статистику. в настоящее время у меня есть консольное приложение, имеющее цикл while (true), который печатает статистику (имя, статус, текущее время выполнения) для каждой операции на экране (обновляя каждую секунду), пока все операции не будут завершены.

Вещь, которая меня беспокоит, это метод async void. Я читал, что это плохая практика, чтобы использовать async void методы, но:

  • Я не могу понять, какой вред они могли бы сделать в моем сценарии
  • Если изменить метод Start вернуть Task, его возвращение значение никогда не будет использоваться в любом месте, и я не могу понять, почему мне нужно

Я был бы признателен, если кто-то может прояснить эти моменты

+1

делать, если дубликат не знает, но может быть: http://stackoverflow.com/questions/12144077/async-wait-when-to-return-a-task-vs-void –

+2

Единственное место, где имеет смысл использовать 'async void', - это когда вам нужно иметь дело с обработчиками событий в контексте синхронизации - контексты синхронизации делают его безопасным, а обработчики событий не должны возвращать значение. Используйте 'async Task' где-нибудь еще - нет причин не делать этого. Ваш код уже выглядит немного подозрительным - например, используя 'Task.Factory.StartNew' вместо' Task.Run' и используя его для запуска асинхронного метода. Почему бы не использовать задачу 'Start', чтобы отслеживать состояние долговременной операции вместо ваших собственных (вероятно, небезопасных) флагов? – Luaan

+0

@ Luaan, я не возвращаю 'Task', потому что мне не нужен объект' Task' в вызывающем коде (я отслеживаю состояние операции usnig другими способами). И если я изменю его, чтобы вернуть «Задача» и сохранить вызов, поскольку он «o.Start()», я получаю предупреждение, предлагающее добавить 'await' к вызову, чего мне совсем не нужно. –

ответ

5

void асинхронного методом является «огнем и забыть» операция , Вы не можете ждать какого-либо результата и не будете знать, когда операция завершится, и если она была успешной или нет.

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

С помощью методов async, которые возвращают Task, вызывающий абонент может ожидать завершения операции, а также обрабатывать исключения, которые произошли во время выполнения операции.

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

+1

Даже для записи типа операций вы никогда не будете использовать void return для асинхронного метода, это их только для событий, которые являются особым случаем –

+1

@MrinalKamboj: «Даже для записи журналов вид операции вы никогда не будете использовать void return» - почему нет? –

+0

@Andre Borges Пожалуйста, проверьте ссылку, предоставленную J Steen выше, которая ответит на ваш вопрос подробно. Даже если вы хотите стрелять и забывать, что вы не хотите делать, не имея никакого контроля над сбоем этого вызова и тем самым влияя на ваш текущий вызов –

0

Ниже два важные вопроса отправленного вами

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

Проверьте следующую ссылку, он уже размещен в комментарии выше и ответов действительно содержит точку вы спрашиваете:

async/await - when to return a Task vs void?

Пль ase понимают, что возвращается void return, чтобы обеспечить совместимость для событий, у которых есть возврат void и их исключения обрабатываются контекстом синхронизации/Ui, иначе для любого другого вызова, почему мы всегда будем полагаться на минимальное возвращение a Task, чтобы избежать исключения в вызове, убивающего процесс, без какого-либо контроля над App Domain unhandled exception, который, таким образом, будет распространяться. Ваш процесс не будет убит без вашего ведома или информации, это большой способ контролировать любой вид вреда вашей системе, даже при запуске огня и забыть

Если я изменил метод «Старт», чтобы вернуть задачу, ее возвращение значение никогда не будет использоваться в любом месте, и я не могу понять, почему мне нужно

Помимо точки, упомянутой выше, связанные с контролем за необработанного исключения, а также рассмотреть этот путь, возвращая Task, у вас есть возможность сделать даже вызывающего абонента Async, если требуется, поскольку только Task может быть awaited, а не пустотой, которая вынуждает t он вызывающий только Synchronous и это будет важным требованием для Web Projects, Web API, которые, возможно, потребуется обслуживание, чтобы быть Asynchronous реализация

Смежные вопросы