2016-06-02 4 views
3

Это то, что я встретил, реорганизовывая некоторый унаследованный код.Различные реализации метода, который возвращает задачу

Рассмотрим метод на интерфейс, который возвращает Task:

public interface IFoo 
{ 
    Task Bar(); 
} 

Реализация Bar метод может быть реализован двумя способами:

возвращающая Task:

public class Foo1 : IFoo 
{ 
    public Task Bar() 
    { 
     return Task.Run(() => 
      { 
       /* some work */ 
      }); 
    } 
} 

Или с помощью async ... await:

public class Foo2 : IFoo 
{ 
    public async Task Bar() 
    { 
     await Task.Run(() => 
      { 
       /* some work */ 
      }); 
    } 
} 

Являются ли эти реализации функционально эквивалентными или существуют (потенциально тонкие) отличия?

+1

Насколько мне известно, разница не такая, как вы здесь представлены. Когда вы реализуете Foo1, вам нужно вызвать Task.Wait() и для Foo2 просто ждать Task, поэтому есть разница. Объясняется здесь: http://stackoverflow.com/questions/9519414/whats-the-difference-between-task-start-wait-and-async-await –

+0

@RazvanDumitru зачем вообще вызывать 'Task.Wait()'? Что касается вызывающих абонентов, оба метода одинаковы. 'await foo1Instance.Bar();' и 'await foo2Instance.Bar();' будет работать одинаково. Нет причин блокировать первый, чтобы вернуть завершенную задачу. , Вы имели в виду что-то еще? –

+0

Да. Верно.Нет необходимости ждать вообще. Вы можете ждать обоих возвращенных объектов. –

ответ

2

Существует большая разница, поскольку использование синтаксиса async-ожидания приводит к тому, что компилятор генерирует код, который фактически продолжается после утверждения ожидания после завершения задачи. Более того, ожидая задачи, которая привела к ошибкам в результате появления пузырька в awaiter, что означает, что он больше не считается ненаблюдаемым. Я думаю, что есть еще что-то, и я действительно рекомендую вам взглянуть на курс Async от C# 5 по методу множественного числа , он на самом деле проходит через код сгенерированного компилятором и объясняет это.

1

Возвращение задачи

Foo1.Bar просто обычный синхронный метод, который возвращает некоторый объект, экземпляр (Task в частности).

Или с помощью асинхр ... ждать

Foo2.Barявляется асинхронный метод, который будет составлен в государственную машину. Здесь будут некоторые накладные расходы. Обратите внимание, что будущая версия Roslyn will convert методов, подобных этому, в синхронные.

Но, на самом деле, вы не должны использовать Task.Run здесь. См. Это замечательный post для деталей.

+0

Это не то, что говорится в статье. В конце концов он * использует * Task.Run. Совет против использования Task.Run в реализации метода для автоматического преобразования метода с привязкой к процессору в «асинхронный» один –

+0

Кроме того, * оба метода являются асинхронными. Оба выполняют свою работу, используя отдельную задачу. Второй, хотя, на самом деле * ожидает * some * other * асинхронного вызова. –

+0

@PanagiotisKanavos: не согласен. 1-й один * * синхронный. Он просто запускает какую-то задачу, но в самом методе нет ничего асинхронного - запуск задачи или поток из метода не делает его асинхронным. Кроме того, вы неправильно понимаете связанную должность. Речь идет о том, чтобы позволить вызывающему пользователю решить, использовать ли «Task.Run» или нет, когда реализация не является «истинным» асинхронным кодом. – Dennis

0

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

Вторая реализация возвращает задачу, которая инкапсулирует еще одну ожидаемую задачу. это приведет к нежелательному раздуванию кода, использованию памяти и, возможно, к созданию другого потока, только для достижения той же цели, что и первая.

+0

Второй фрагмент кода позволяет выполнять больше кода после завершения задачи, при условии, что исключение не выбрасывается. В любом случае цели не обсуждались - вопрос вращается вокруг разницы между ними. –

+0

@EyalPerry это неверно. Вы можете использовать 'ContinueWith' для запуска кода после завершения задачи. Вот как Tasks использовались в .NET 4.0 и * still *, когда машина состояний, генерируемая 'async/await', нежелательна –

+0

То, что вы сказали, верно, но не отрицает, что я сказал .. @PanagiotisKanavos –