В чем разница между возвращением void и возвращением задачи?



при просмотре различных образцов C# Async CTP я вижу некоторые асинхронные функции, которые возвращают void и другие, которые возвращают необщего Task. Я могу понять, почему возвращение Task<MyType> полезно возвращать данные вызывающему при завершении асинхронной операции, но функции, которые я видел, имеют тип возврата Task никогда не возвращает никаких данных. Почему бы не вернуться void?

790   4  

4 ответов:

ответы SLaks и Killercam хороши; я думал, что просто добавлю немного больше контекста.

ваш первый вопрос по существу о том, какие методы могут быть отмечены async.

метод помечен как async может возвратить void,Task или Task<T>. В чем разница между ними?

A Task<T> возвращение асинхронного метода можно ожидать, и когда задача завершится, он предложит T.

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

A void возвращение асинхронного метода нельзя ожидать; это метод" огонь и забыть". Он работает асинхронно, и вы не можете сказать, когда это будет сделано. Это более чем немного странно; как говорит Слакс, обычно вы делаете это только при создании асинхронного обработчика событий. Событие срабатывает, обработчик выполняется; никто не собирается "ждать задача, возвращаемая обработчиком событий, потому что обработчики событий не возвращают задачи, и даже если они это сделали, какой код будет использовать задачу для чего-то? Обычно это не пользовательский код, который передает управление обработчику в первую очередь.

ваш второй вопрос, в комментарии, по сути, о том, что может быть awaitЭд:

какие методы могут быть awaitЭд? Может ли метод void-returning быть awaitЭд?

нет, пустота-возвращение метод нельзя ждать. Компилятор переводит await M() в вызов M().GetAwaiter(), где GetAwaiter может быть метод экземпляра или метода расширения. Ожидаемое значение должно быть таким, для которого вы можете получить ожидающего; ясно, что метод возврата пустоты не создает значение, из которого вы можете получить ожидающего.

Task-возвращаемые методы могут создавать ожидаемые значения. Мы ожидаем, что третьи стороны захотят создать свои собственные реализации Task-как объекты, которые можно ждать, и вы сможете их дождаться. Однако вам не будет разрешено объявлять async методы, которые возвращают все, кроме void,Task или Task<T>.

(обновление: мое последнее предложение может быть фальсифицировано будущей версией C#; есть предложение разрешить возвращаемые типы, отличные от типов задач, для асинхронных методов.)

(обновление: упомянутая выше функция сделала это в C# 7.)

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

на самом деле, единственная причина, чтобы вернуться void Если вы не может возвращение Task потому что вы пишете обработчик событий.

методы возврата Task и Task<T> являются составными-это означает, что вы можете await их внутри async метод.

async методы возврата void не являются составными, но они имеют два других важных свойства:

  1. они могут быть использованы в качестве обработчиков событий.
  2. они представляют собой асинхронную операцию "верхнего уровня".

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

ASP.NET контекст является одним из таких контекстов; если вы используете async Task методы, не ожидая их от асинхронного void метод, затем ASP.NET запрос будет выполнен слишком рано.

другой контекст-это AsyncContext я написал для модульного тестирования (доступно здесь) - the AsyncContext.Run метод отслеживает количество выдающихся операций и возвращает, когда оно равно нулю.

тип Task<T> - Это тип рабочей лошадки параллельной библиотеки задач (TPL), он представляет собой понятие "некоторая работа/задание, которое будет производить результат типа T в будущем". Понятие "работа, которая завершится в будущем, но не вернет результата" представлено неродовым типом задачи.

точно как результат типа T будет производиться is и детали реализации конкретной задачи; работа может быть передана в другой процесс на локальной машине, в другой поток и т. д. Задачи TPL обычно распределяются по рабочим потокам из пула потоков в текущем процессе, но эта деталь реализации не является фундаментальной для Task<T> тип; скорее a Task<T> может представлять любую операцию с высокой задержкой, которая создает T.

на основе вашего комментария выше:

The await выражение означает "оценить это выражение, чтобы получить объект, представляющий работу, которая будет в будущем произведите результат. Зарегистрируйте оставшуюся часть текущего метода как обратный вызов, связанный с продолжением этой задачи. Как только эта задача будет выполнена и обратный вызов зарегистрирован, тут вернуть управление моему абоненту". Это противопоставляется / в отличие от обычного вызова метода, что означает " помните, что вы делаете, запустите этот метод, пока он не будет полностью завершен, а затем поднимите, где вы остановились, теперь зная результат метод."


Edit: я должен процитировать статью Эрика Липперта в октябре 2011 года в журнале MSDN, поскольку это было большим подспорьем для меня в понимании этого материала в первую очередь.

для нагрузок больше информации и ознакомиться с программой здесь.

Я надеюсь, что это поможет.

Comments

    Ничего не найдено.