В чем разница между возвратом пустоты и возвратом задачи?
При просмотре различных образцов C # Async CTP я вижу некоторые функции async, которые возвращают void
, и другие, которые возвращают не-общую Task
. Я вижу, почему возrotation Task
полезно возвращать данные вызывающему, когда операция async завершается, но функции, которые я видел, которые возвращают тип Task
никогда не возвращают какие-либо данные. Почему бы не вернуть void
?
- Вызов синхронного асинхронного метода
- Секвенирование и реорганизация задач
- Каков правильный способ отмены асинхронной операции, которая не принимает CancellationToken?
- Использовать Task.Run () в синхронном методе, чтобы избежать тупиковой остановки в асинхронном методе?
- Почему это асинхронное действие зависает?
- WaitAll vs WhenAll
- Разница между TPL и async / await (Обработка streamов)
- Запуск нескольких задач async и ожидание их завершения
Ответы SLaks и Killercam хорошие; Я думал, что просто добавлю немного больше контекста.
Ваш первый вопрос в основном о том, какие методы могут быть помечены как async
.
Метод, помеченный как
async
может возвращатьvoid
,Task
илиTask
. Каковы различия между ними?
Ожидается, что метод async, возвращающий Task
может быть ожидаемым, и когда задача завершится, он предложит T.
Ожидается, что метод async, возвращающий задачу, можно ожидать, и когда задача завершается, планируется запуск задачи.
Ожидаемый метод асинхронного ввода void
; это метод «огонь и забыть». Он работает асинхронно, и вы не можете сказать, когда это будет сделано. Это более чем немного странно; как говорит SLaks, обычно вы делаете это только при создании асинхронного обработчика событий. Событие срабатывает, выполняется обработчик; никто не собирается «ждать» задачи, возвращенной обработчиком событий, потому что обработчики событий не возвращают задачи, и даже если бы они и делали, какой код использовал бы что-то? Обычно это не код пользователя, который в первую очередь передает управление обработчику.
Ваш второй вопрос, в комментарии, в основном о том, что можно await
:
Какие методы можно
await
? Может ли ожидаемый метод возврата пустоты?
Нет, метод ожидания возврата не может быть ожидаемым. Компилятор переводит await M()
в вызов M().GetAwaiter()
, где GetAwaiter
может быть методом экземпляра или методом расширения. Ожидаемое значение должно быть таким, за которое вы можете получить awaiter; очевидно, что метод возврата void не дает значения, из которого вы можете получить awaiter.
Task
– методы возврата могут вызывать ожидаемые значения. Мы ожидаем, что третьи стороны захотят создать свои собственные объекты Task
like, которые можно ожидать, и вы сможете их подождать. Однако вам не будет разрешено объявлять методы async
которые возвращают что-либо, кроме void
, Task
или Task
.
(ОБНОВЛЕНИЕ: Мое последнее предложение может быть сфальсифицировано будущей версией C #, есть предложение разрешить типы возврата, отличные от типов задач для методов async.)
(ОБНОВЛЕНИЕ: упомянутая выше функция сделала это до C # 7.)
В случае, если вызывающий абонент хочет ждать выполнения задачи или добавить продолжение.
Фактически, единственной причиной возврата void
является то, что вы не можете вернуть Task
потому что вы пишете обработчик событий.
Методы, возвращающие Task
и Task
являются составными, что означает, что вы можете await
их внутри метода async
.
async
методы, возвращающие void
, не являются составными, но у них есть еще два важных свойства:
- Они могут использоваться как обработчики событий.
- Они представляют собой асинхронную операцию «верхнего уровня».
Второй момент важен, когда вы имеете дело с контекстом, который поддерживает количество выдающихся асинхронных операций.
Контекст ASP.NET – один из таких контекстов; если вы используете методы async Task
не ожидая их из метода async void
, запрос ASP.NET будет завершен слишком рано.
Другим контекстом является AsyncContext
я написал для модульного тестирования (доступно здесь ). Метод AsyncContext.Run
отслеживает выдающийся счетчик операций и возвращает его, когда он равен нулю.
Тип Task
– тип рабочей лошади параллельной библиотеки задач (TPL), он представляет собой концепцию «некоторая работа / работа, которая в будущем приведет к результату типа T
». Концепция «работа, которая будет завершена в будущем, но не возвращает результат», представлена не-общим типом задачи.
Именно то, как будет производиться результат типа T
– это и детализация реализации конкретной задачи; работа может быть обработана другим процессом на локальной машине, другим streamом и т. д. Задачи TPL обычно обрабатываются рабочими streamами из пула streamов в текущем процессе, но эта деталь реализации не является фундаментальной для Task
тип; скорее Task
может представлять любую операцию с высокой задержкой, которая создает T
Основываясь на вашем комментарии выше:
Выражение await
означает «оценить это выражение, чтобы получить объект, представляющий работу, которая в будущем приведет к результату». Подпишите оставшуюся часть текущего метода как обратный вызов, связанный с продолжением этой задачи. После создания этой задачи и вызова назад зарегистрировано, немедленно верните управление моему абоненту ». Это противоположно / в отличие от обычного вызова метода, что означает «помните, что вы делаете, запускайте этот метод до тех пор, пока он не будет полностью закончен, а затем заберите, где вы остановились, теперь зная результат метода».
Редактировать: Я должен привести статью Эрика Липперта в октябре 2011 года в MSDN Magazine, так как это очень помогло мне в понимании этого материала в первую очередь.
Для нагрузок больше информации и белых страниц см. Здесь .
Надеюсь, это поможет.