В этой статье MSDN приведен следующий пример кода (слегка отредактированный для краткости):
public async Task<ActionResult> Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Department department = await db.Departments.FindAsync(id);
if (department == null)
{
return HttpNotFound();
}
return View(department);
}
FindAsync
Метод возвращает Department
объект по его ID, и возвращает Task<Department>
. Затем отдел немедленно проверяется, чтобы узнать, является ли он нулевым. Насколько я понимаю, запрос значения задачи таким образом будет блокировать выполнение кода до тех пор, пока не будет возвращено значение ожидаемого метода, что фактически делает это синхронным вызовом.
Зачем тебе это делать? Не проще ли будет просто вызвать синхронный метод Find(id)
, если вы все равно собираетесь немедленно заблокировать?
c#
.net
asp.net-mvc
async
Роберт Харви
источник
источник
... else return null;
Затем вам нужно проверить, что метод действительно нашел тот отдел, о котором вы просили.Ответы:
Не совсем.
При вызове
await db.Departments.FindAsync(id)
задача отсылается и текущий поток возвращается в пул для использования другими операциями. Поток выполнения блокируется (как это было бы независимо от использованияdepartment
сразу после этого, если я правильно понимаю вещи), но сам поток может свободно использоваться другими вещами, пока вы ожидаете завершения операции вне машины (и сигнализируется событием или портом завершения).Если вы позвонили,
d.Departments.Find(id)
поток действительно сидит и ждет ответа, хотя большая часть обработки выполняется в БД.Вы эффективно освобождаете ресурсы процессора, когда диск привязан.
источник
await
что нужно, это подписать оставшуюся часть метода как продолжение в том же потоке (есть исключения; некоторые асинхронные методы раскручивают свой собственный поток) или подписатьasync
метод как продолжение в том же потоке и разрешить оставшийся код для выполнения (как вы можете видеть, я не совсем ясно, какasync
работает). То, что вы описываете, звучит больше как сложная формаThread.Sleep(untilReturnValueAvailable)
ConfigureAwait
iirc).await
обратиться к нейpublic async Task<ActionResult> Details(int? id)
. В противном случае исходный вызов просто заблокируется, ожидаяdepartment == null
разрешения.await ...
«возвращается»FindAsync
вызов закончен. Это то, что ждет. Он называется await, потому что он заставляет ваш код ждать чего-то. (Но учтите, что это не то же самое, что заставлять текущий поток ждать чего-либо)Я действительно ненавижу, что ни один из примеров не показывает, как можно подождать несколько строк, прежде чем ждать задания. Учти это.
Это тот код, который поощряют примеры, и вы правы. В этом мало смысла. Он освобождает основной поток для выполнения других задач, таких как реагирование на ввод пользовательского интерфейса, но реальная сила async / await в том, что я могу легко продолжать выполнять другие действия, ожидая завершения потенциально долго выполняемой задачи. Приведенный выше код «заблокирует» и будет ждать выполнения строки печати, пока мы не получим Foo & Bar. Там нет необходимости ждать, хотя. Мы можем обработать это, пока мы ждем.
Теперь, с переписанным кодом, мы не останавливаемся и не ждем наших значений, пока мы не должны. Я всегда в поисках таких возможностей. Быть умным во время ожидания может привести к значительному улучшению производительности. В наши дни у нас есть несколько ядер, и мы могли бы их использовать.
источник
await
и позволяете потоку делать совершенно разные вещи.Так что здесь происходит нечто большее за кулисами. Async / Await - синтаксический сахар. Сначала посмотрите на сигнатуру функции FindAsync. Возвращает задание. Вы уже видите магию ключевого слова, оно распаковывает эту задачу в отдел.
Вызывающая функция не блокируется. Что происходит, так это то, что присвоение отделу и всему, что следует за ключевым словом await, помещается в замыкание и для всех намерений и целей передается методу Task.ContinueWith (функция FindAsync автоматически выполняется в другом потоке).
Конечно, за кулисами происходит нечто большее, потому что операция перенаправляется обратно в исходный поток (так что вам больше не нужно беспокоиться о синхронизации с пользовательским интерфейсом при выполнении фоновой операции), а в случае вызова функции Async ( и вызывается асинхронно) то же самое происходит в стеке.
Итак, что происходит, вы получаете магию асинхронных операций, без ошибок.
источник
Нет, это не возвращается сразу. Ожидание делает вызов метода асинхронным. Когда вызывается FindAsync, метод Details возвращает задание, которое не выполнено. Когда FindAsync завершит работу, он вернет свой результат в переменную отдела и возобновит работу остальной части метода Details.
источник
async
await
как правило, не создает новые потоки, и даже если это произошло, вам все равно нужно подождать, пока значение этого отдела не выяснит, является ли оно нулевым.public async Task<ActionResult>
необходимо такжеawait
await
Не следует смешивать с.Wait()
или.Result
, так как это может вызвать взаимные блокировки. Цепочка async / await обычно заканчивается функцией сasync void
сигнатурой, которая в основном используется для обработчиков событий или для функций, вызываемых непосредственно элементами пользовательского интерфейса.Мне нравится думать об «асинхронности» как о контракте, о контракте, который говорит: «Я могу выполнить это асинхронно, если вам это нужно, но вы также можете вызывать меня как любую другую синхронную функцию».
Это означало, что один разработчик делал функции, и некоторые дизайнерские решения заставили их сделать / пометить группу функций как «асинхронные». Вызывающий / потребитель функций может использовать их по своему усмотрению. Как вы говорите, вы можете либо вызвать await прямо перед вызовом функции и ждать его, таким образом, вы рассматриваете это как синхронную функцию, но если вы хотите, вы можете вызвать ее без await как
и после, скажем, 10 строк вниз функции, которую вы вызываете
следовательно, рассматривая это как асинхронную функцию.
Тебе решать.
источник
«если вы собираетесь немедленно заблокировать», ответ «Да». Только когда вам нужен быстрый ответ, ожидание / асинхронность имеют смысл. Например, поток пользовательского интерфейса переходит к действительно асинхронному методу, поток пользовательского интерфейса вернется и продолжит прослушивать нажатие кнопки, в то время как код ниже «await» будет выполнен другим потоком и, наконец, получит результат.
источник