2014-10-13 3 views
1

Рассмотрим этот метод:Async void или Task.Run?

public Status SendMessage(InParam inParam) 
{ 
    try 
    { 
     Task.Run(() => MethodAsync(inParam)); 
     return Status.Success; 
    } 
    catch (Exception ex) 
    { 
     // Log the exception 
     return Status.Failed; 
    } 
} 

Метод MethodAsync:

public async Task<Status> MethodAsync(InParam inParam) 
{ 
    try 
    { 
     return await processor.Process(inParam); 
    } 
    catch (Exception ex) 
    { 
     // Log exception 
     return Status.Failed; 
    } 
} 

и метод процесса:

public async Task<Status> Process(InParam inParam) 
{ 
    try 
    { 
     IMessage endpoint = (IMessage)Activator 
      .CreateInstance(Type.GetType(_message.AgentDLLName), args); 
     _messageDispatchers.Add(endpoint); 

     foreach (IMessage dispatcher in _messageDispatchers) 
     { 
      await Task.Run(() => dispatcher.SendMessage(_message)); 
     } 
     return await Task.Run(() => Status.Success); 
    } 
    catch (Exception ex) 
    { 
     // Log exception 
     return Status.Failed; 
    } 

} 

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

Я пытаюсь сделать SendMessage вызов MethodAsync и не должен ждать его возврата. Я прочитал, что в асинхронном рабочем процессе полный стек должен быть асинхронным, чтобы он работал правильно. SendMessage не помечен async.

Правильно ли это вызов метода MethodAsync, поскольку Task.Run возвращает ожидаемый?

+4

'return wait Task.Run (() => Status.Success);' - эта строка выглядит так, как будто это должно быть 'return Status.Success', no? –

+0

Спасибо, что указали это. Это на самом деле находится в производственном коде, а не опечатка. Я добавил цикл for теперь в вопросе, который я пропустил раньше. – Codehelp

+0

@Codehelp: Все еще не имеет никакого смысла. 'return wait Task.Run (() => Status.Success);' приводит к той же логике, что и 'return Status.Success;', но вызовет дополнительный контекст-переключатель, который просто тратит время CPU ... – ChrFin

ответ

1

MethodAsync отмечен как async звонок Task.Run(() => MethodAsync(inParam)); не имеет смысла.
Если вы хотите реализовать его как «огонь и забыть» -Call (BAD кстати), вы можете просто позвонить MethodAsync(inParam);, потому что это также запускает метод await ред внутри MethodAsync «в своей собственной задаче "(упрощенный) и возвращает это. Если вы тогда не «ждете, что это будет возможно», ваш код внутри SendMessage будет продолжать выполнять, пока он все еще работает.

НО, как уже говорилось: «« Огонь и забыть »« Плохой дизайн практически во всех случаях. Можете ли вы объяснить свой прецедент немного больше, поэтому мы можем предложить лучший подход?

UPDATE:
Если нет действительно никакого способа, либо сделать SendMessageasync или имеют синхронный аналог MethodAsync я рекомендую следующее:

public Status SendMessage(InParam inParam) 
{ 
    try 
    { 
     return AsyncPump.Run(() => MethodAsync(inParam)); 
    } 
    catch (Exception ex) 
    { 
     // Log the exception 
     return Status.Failed; 
    } 
} 

Использование AsyncPump вы можете вернуть «реальный результат «и не имеют проблем с блокировкой.
В вашем примере реализация SendMessagetry/catch также имеет меньшее значение, так как метод, скорее всего, вернется к пути до того, как произойдет любое изъятие внутри MethodAsync.

UPDATE 2 (после того, как обновленный вопрос):
я рекомендовал бы "идти async весь путь". Значение также делает SendMessageasync (и все методы до пользовательского интерфейса), поэтому вы можете await «реальный результат», но не блокируйте интерфейс, пока вы ждете ...

UPDATE 3:
Я хотел бы также изменить

foreach (IMessage dispatcher in _messageDispatchers) 
{ 
    await Task.Run(() => dispatcher.SendMessage(_message)); 
} 

в

await Task.Run(() => 
    { 
     foreach (IMessage dispatcher in _messageDispatchers) 
      dispatcher.SendMessage(_message); 
    }); 

Это casues меньше контекстно-переключателей. Или даже:

await Task.Run(() => Parallel.ForEach(_messageDispatchers, d => d.SendMessage(_message))); 
+0

оцените ваше время и ответ. Процесс запускается из приложения MVC, поэтому блокировка пользовательского интерфейса не произойдет, я думаю! Нет? – Codehelp

+0

@Codehelp: Ах, MVC. Нет, нет «UI блокируется», но запрос не будет завершен. Взгляните на http://blogs.msdn.com/b/webdev/archive/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-long-background-process-in-asp-net. aspx, чтобы запустить его в фоновом режиме. Но вы всегда будете «потерять результат», если вы не дождались его ... – ChrFin

+1

Этот _ «асинхронный путь» _ вирус начинает пахнуть куском груза. Переустановите свою кодовую базу для ... причин. 'TaskCompletionSource' может помочь вам подделать метод async с устаревшим кодом с очень небольшим количеством ошибок. – Gusdor

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