Из моего понимания одной из главных вещей , которые async
иawait
делает это , чтобы сделать код легко писать и читать - но используют их равный нерест фоновых потоков для выполнения длинной логики продолжительности?
Я сейчас пробую самый простой пример. Я добавил несколько комментариев. Можете ли вы уточнить это для меня?
// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
Task<int> access = DoSomethingAsync();
// task independent stuff here
// this line is reached after the 5 seconds sleep from
// DoSomethingAsync() method. Shouldn't it be reached immediately?
int a = 1;
// from my understanding the waiting should be done here.
int x = await access;
}
async Task<int> DoSomethingAsync()
{
// is this executed on a background thread?
System.Threading.Thread.Sleep(5000);
return 1;
}
c#
.net
asynchronous
async-await
Дан Дину
источник
источник
Ответы:
При использовании
async
иawait
компилятор генерирует конечный автомат в фоновом режиме.Вот пример, на котором я надеюсь, что смогу объяснить некоторые детали высокого уровня, которые происходят:
Итак, что здесь происходит:
Task<int> longRunningTask = LongRunningOperationAsync();
начинает выполнятьLongRunningOperation
Независимая работа сделана, давайте предположим, что основной поток (Thread ID = 1) тогда
await longRunningTask
достигнут.Теперь, если функция
longRunningTask
еще не завершена и она все еще выполняется,MyMethodAsync()
вернется к своему вызывающему методу, поэтому основной поток не будет заблокирован. Когда этоlongRunningTask
будет сделано, поток из ThreadPool (может быть любым потоком) вернетсяMyMethodAsync()
в свой предыдущий контекст и продолжит выполнение (в этом случае выводит результат на консоль).Вторым случаем может быть то, что
longRunningTask
он уже завершил свое выполнение, и результат доступен. При достиженииawait longRunningTask
мы уже имеем результат, поэтому код будет продолжать выполняться в том же потоке. (в этом случае результат печати выводится на консоль). Конечно, это не относится к приведенному выше примеру, где естьTask.Delay(1000)
участие.источник
Они должны сделать асинхронный код простым для написания и чтения, да.
Не за что.
async
Ключевое слово позволяетawait
ключевое слово. Таким образом, любой метод использованияawait
должен быть отмеченasync
.Нет, потому что
async
методы не запускаются в другом потоке по умолчанию.Нет.
Вы можете найти мое
async
/await
вступление полезным. В официальных документах MSDN также необычно хорошо (особенно TAP раздел), иasync
команда сделала отличный FAQ .источник
async
методы не запускаются в другом потоке по умолчанию. В вашем примере,Sleep()
вызов внутриDoSomethingAsync()
блокирует текущий поток, который препятствует продолжению выполненияbutton1_Click()
доDoSomethingAsync()
завершения. Обратите внимание, что whileThread.Sleep()
блокирует исполняющий поток,Task.Delay() does not.
объяснение
Вот быстрый пример
async
/await
на высоком уровне. Помимо этого есть еще много деталей, которые следует рассмотреть.Примечание:
Task.Delay(1000)
имитирует выполнение работы в течение 1 секунды. Я думаю, что лучше всего думать об этом как об ожидании ответа от внешнего ресурса. Поскольку наш код ожидает ответа, система может отложить текущее задание в сторону и вернуться к нему после его завершения. Между тем, он может выполнять другую работу в этом потоке.В приведенном ниже примере, первый блок делает именно это. Он сразу запускает все задачи (
Task.Delay
линии) и откладывает их в сторону. Код будет приостанавливаться вawait a
строке, пока не будет сделана задержка в 1 секунду, прежде чем перейти к следующей строке. Так какb
,c
,d
иe
все приступили к выполнению почти в то же самое время , какa
(из - за отсутствие ОЖИДАНИЯ), они должны закончить примерно в то же время в данном случае.В приведенном ниже примере второй блок запускает задачу и ожидает ее завершения (вот что
await
делает) перед запуском последующих задач. Каждая итерация этого занимает 1 секунду. Программаawait
приостанавливает работу программы и ждет результата, прежде чем продолжить. В этом главное отличие первого и второго блоков.пример
ВЫВОД:
Дополнительная информация о SynchronizationContext
Примечание: это то, что для меня немного туманно, так что если я ошибаюсь, поправьте меня, и я обновлю ответ. Важно иметь общее представление о том, как это работает, но вы можете обойтись без того, чтобы быть экспертом в этом, пока вы никогда не используете
ConfigureAwait(false)
, хотя, я полагаю, вы потеряете некоторые возможности для оптимизации.Есть один аспект, который делает
async
/await
концепцию несколько сложнее понять. Это тот факт, что в этом примере все это происходит в одном и том же потоке (или, по крайней мере, в том, что касается одного и того же потокаSynchronizationContext
). По умолчаниюawait
восстанавливает контекст синхронизации исходного потока, в котором он работал. Например, в ASP.NET у вас есть объект,HttpContext
привязанный к потоку при поступлении запроса. Этот контекст содержит вещи, характерные для исходного запроса Http, такие как исходный объект запроса, который имеет такие вещи, как язык, IP-адрес, заголовки и т. Д. Если вы переключаете потоки на полпути при обработке чего-либо, вы можете в конечном итоге попытаться извлечь информацию из этого объекта на другомHttpContext
что может быть катастрофическим. Если вы знаете, что ни для чего не будете использовать контекст, вы можете выбрать «не заботиться» об этом. Это в основном позволяет вашему коду запускаться в отдельном потоке, не привнося в него контекст.Как вы этого добиваетесь? По умолчанию
await a;
код фактически предполагает, что вы действительно хотите захватить и восстановить контекст:Если вы хотите, чтобы основной код продолжал работу в новом потоке без исходного контекста, вы просто используете false вместо true, чтобы он знал, что не нужно восстанавливать контекст.
После того, как программа будет приостановлена, она потенциально будет продолжаться в совершенно другом потоке с другим контекстом. Отсюда и повышение производительности - оно может продолжаться в любом доступном потоке без восстановления исходного контекста, с которого он начал.
Это что-то смущает? Да, черт возьми! Вы можете понять это? Вероятно! Как только вы овладеете концепциями, перейдите к объяснениям Стивена Клири, которые, как правило, больше ориентированы на кого-то, у кого уже есть техническое понимание
async
/await
уже.источник
await MethodCall()
это абсолютная трата? Вы могли бы также броситьawait
/async
?await
, я думаю, что он освобождает поток обратно в пул, а не удерживает его. Это делает его доступным для использования в другом месте, ожидая возвращения заданияВ дополнение к другим ответам взгляните на await (C # Reference)
и более конкретно в приведенном примере, это немного объясняет вашу ситуацию
источник
Task.Delay
срабатывании таймера .Показаны приведенные выше объяснения в действии в простой консольной программе:
И вывод:
Таким образом,
TestAsyncAwaitMethods
. Это немедленно возвращается без остановки текущего потока, и мы сразу же видим сообщение «Нажмите любую клавишу для выхода»LongRunningMethod
работает в фоновом режиме. После его завершения другой поток из Threadpool выбирает этот контекст и отображает последнее сообщение.Таким образом, не поток заблокирован.
источник
return 1
часть заслуживает дополнительного пояснения:await
ключевое слово позволяет вамTask<T>
напрямую возвращать базовый тип , тем самым облегчая адаптацию вашего кода выхода в мир await / async . Но вам не нужно возвращать значение, так как можно вернуть aTask
без указания возвращаемого типа, который будет эквивалентен синхронномуvoid
методу. Имейте в виду, что C # допускаетasync void
методы, но вам следует избегать этого, если вы не занимаетесь обработчиками событий.Я думаю, что вы выбрали плохой пример с
System.Threading.Thread.Sleep
Суть
async
задачи состоит в том, чтобы он выполнялся в фоновом режиме, не блокируя основной поток, например, делаяDownloadFileAsync
System.Threading.Thread.Sleep
это не то, что «делается», это просто спит, и поэтому ваша следующая строка достигается через 5 секунд ...Прочитайте эту статью, я думаю, что это отличное объяснение
async
иawait
концепция: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspxисточник
Thread.Sleep
блокирует поток (поток не может делать ничего другого, кроме простоя), но асинхронный метод этого не делает. В случаеDownloadFileAsync
, поток может пойти и сделать что-то еще, пока не придет ответ от удаленного сервера. Лучшим заполнителем для «некоторой задачи, которая требует времени» в асинхронном методе, является тоTask.Delay
, что это на самом деле асинхронно.async
ключевое слово. Но его метод все еще работал синхронно, и этот ответ прекрасно объяснил почему: потому что он фактически не выполнял асинхронный код. Отмеченные методы по-async
прежнему работают синхронно до тех пор, пока выawait
не завершитеTask
. Если нетawait
, метод работает синхронно, и компилятор предупредит вас об этом.Вот быстрая консольная программа, чтобы она была понятна тем, кто следит за ней.
TaskToDo
Метод вашего длинный метод работает , что вы хотите сделать асинхра. Выполнение асинхронного запуска выполняетсяTestAsync
методом. Метод test loop просто выполняетTaskToDo
задачи и запускает их асинхронно. Вы можете видеть это в результатах, потому что они не выполняются в одном и том же порядке от запуска к запуску - они сообщают потоку пользовательского интерфейса консоли, когда завершают работу. Упрощенно, но я думаю, что упрощенные примеры лучше раскрывают суть шаблона, чем более сложные примеры:источник
Для быстрого обучения ..
Разобраться в потоке выполнения метода (с диаграммой): 3 минуты
Вопрос самоанализ (ради обучения): 1 мин
Быстро пройти через синтаксис сахара: 5 минут
Поделитесь смущением разработчика: 5 минут
Проблема: Быстрое изменение реальной реализации нормального кода на асинхронный код: 2 минуты
Куда дальше?
Разобраться в потоке выполнения метода (с диаграммой): 3 минуты
На этом изображении, просто сфокусируйтесь на # 6 (больше ничего)
На шаге № 6: выполнение здесь остановлено, так как оно закончилось без работы. Для продолжения нужен результат из getStringTask (вид функции). Следовательно, он использует
await
оператор, чтобы приостановить свой прогресс и вернуть управление (yield) вызывающей стороне (в этом методе мы находимся). Фактический вызов getStringTask был сделан ранее в # 2. На # 2 было обещано вернуть строковый результат. Но когда он вернет результат? Должны ли мы (# 1: AccessTheWebAsync) повторить второй вызов? Кто получает результат, № 2 (оператор вызова) или № 6 (ожидание заявления)Внешний абонент AccessTheWebAsync () также ждет. Поэтому вызывающая сторона ожидает AccessTheWebAsync, а AccessTheWebAsync в данный момент ожидает GetStringAsync. Интересно, что AccessTheWebAsync проделал некоторую работу перед ожиданием (# 4), возможно, чтобы сэкономить время на ожидании. Та же свобода для многозадачности также доступна для внешнего абонента (и всех абонентов в цепочке), и это самый большой плюс этой «асинхронной» штуки!Вы чувствуете, что это синхронно ... или нормально, но это не так.
Помните, что метод уже был возвращен (# 2), он не может вернуться снова (без второго раза). Так как же узнает звонящий? Это все о задачах! Задача была выполнена. Задача ожидалась (не метод, не значение). Значение будет установлено в Задаче. Статус задачи будет установлен для завершения. Вызывающий просто следит за задачей (# 6). Таким образом, 6 # - это ответ на вопрос, где / кто получает результат. Далее читайте позже здесь .
Вопрос самоанализ для изучения сакэ: 1 мин
Давайте немного подправим вопрос:
Потому что обучение
Task
автоматически охватывает два других (и отвечает на ваш вопрос)Быстро пройти через синтаксис сахара: 5 минут
До конвертации (оригинальный метод)
internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }
Task-ified метод для вызова вышеуказанного метода
internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }
Мы упомянули await или async? Нет. Вызовите вышеуказанный метод, и вы получите задачу, которую можете отслеживать. Вы уже знаете, что возвращает задание .. целое число.
Вызов задачи немного сложен, и именно тогда ключевые слова начинают появляться. Давайте назовем MethodTask ()
internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }
Тот же код выше добавлен как изображение ниже:
await
async
(обязательный синтаксис)Async
префиксом (стандарт кодирования)await
это легко понять, но остальные два (async
,Async
) могут не быть :). Ну, это должно сделать намного больше смысла компилятор though.Further читает для последующего использования здесьПоделитесь смущением разработчика: 5 минут
Разработчик допустил ошибку, не реализовав,
Task
но это все еще работает! Постарайтесь понять вопрос и просто принятый ответ, приведенный здесь . Надеюсь, что вы прочитали и полностью поняли. Суть в том, что мы можем не видеть / реализовывать «Задачу», но она реализована где-то в родительском классе. Аналогично, в нашем примере вызов уже созданногоMethodAsync()
способа проще, чем реализация этого метода с помощьюTask
(MethodTask()
). Большинству разработчиков трудно передуматьTasks
при преобразовании кода в асинхронный.Совет: попробуйте найти существующую реализацию Async (например,
MethodAsync
илиToListAsync
), чтобы передать сложность на аутсорсинг. Таким образом, нам нужно иметь дело только с Async и await (что легко и очень похоже на обычный код)Проблема: быстро изменить реальную реализацию нормального кода на асинхронную работу: 2 минуты
Строка кода, показанная ниже в Data Layer, начала ломаться (много мест). Потому что мы обновили часть нашего кода с .Net Framework 4.2. * До ядра .Net. Мы должны были исправить это за 1 час по всему приложению!
очень просто!
Async
иawait
в коде.строка вызывающего кода изменилась следующим образом
Подпись метода изменена с
Contract GetContract(int contractnumber)
в
async Task<Contract> GetContractAsync(int contractnumber)
вызывающий метод также пострадал:
GetContractAsync(123456);
был вызван какGetContractAsync(123456).Result;
Мы изменили его везде за 30 минут!
Но архитектор сказал нам не использовать библиотеку EntityFramework только для этого! упс! драма! Затем мы сделали пользовательскую реализацию Задачи (юк). Который ты знаешь как. Все еще легко! .. еще юк ..
Куда дальше? В ASP.Net Core мы могли бы посмотреть замечательное короткое видео о преобразовании синхронных вызовов в асинхронные , возможно, именно в этом направлении можно было бы двигаться после прочтения этого.
источник
Все ответы здесь используют
Task.Delay()
или какую-то другую встроеннуюasync
функцию. Но вот мой пример, который не использует ни одну из этихasync
функций:источник
task.Wait();
и как его можно использовать, чтобы избежать асинхронного / ожидающего ада: PЭтот ответ призван предоставить некоторую информацию, относящуюся к ASP.NET.
Используя async / await в контроллере MVC, можно увеличить использование пула потоков и добиться гораздо лучшей пропускной способности, как объясняется в следующей статье:
http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4
источник
Async & Await Simple Explanation
Простая аналогия
Человек может ждать своего утреннего поезда. Это все, что они делают, поскольку это их основная задача, которую они выполняют в настоящее время. (синхронное программирование (что вы обычно делаете!))
Другой человек может ждать своего утреннего поезда, пока он курит сигарету и затем пьет свой кофе. (Асинхронное программирование)
Что такое асинхронное программирование?
Асинхронное программирование - это когда программист решает запустить часть своего кода в отдельном потоке от основного потока выполнения, а затем уведомить основной поток о его завершении.
Что на самом деле делает ключевое слово async?
Префикс асинхронного ключевого слова к имени метода, например
позволяет программисту использовать ключевое слово await при вызове асинхронных задач. Это все, что он делает.
Почему это важно?
Во многих программных системах основной поток зарезервирован для операций, конкретно относящихся к пользовательскому интерфейсу. Если на моем компьютере запущен очень сложный рекурсивный алгоритм, выполнение которого занимает 5 секунд, но я запускаю его в основном потоке (поток пользовательского интерфейса). Когда пользователь пытается щелкнуть что-либо в моем приложении, оно будет заморожено. поскольку мой основной поток поставлен в очередь и в настоящее время обрабатывает слишком много операций. В результате основной поток не может обработать щелчок мыши, чтобы запустить метод от нажатия кнопки.
Когда вы используете Async и Await?
Идеально используйте асинхронные ключевые слова, когда вы делаете что-то, что не связано с пользовательским интерфейсом.
Допустим, вы пишете программу, которая позволяет пользователю делать наброски на своем мобильном телефоне, но каждые 5 секунд он будет проверять погоду в Интернете.
Мы должны ждать звонка, который каждые 5 секунд вызывает опрос, чтобы узнать погоду, так как пользователь приложения должен продолжать взаимодействовать с мобильным сенсорным экраном, чтобы рисовать красивые картинки.
Как вы используете Async и Await
Исходя из приведенного выше примера, вот некоторый псевдокод того, как его написать:
Дополнительные примечания - Обновление
Я забыл упомянуть в своих оригинальных заметках, что в C # вы можете только ждать методы, которые обернуты в Задачи. например, вы можете дождаться этого метода:
Вы не можете ждать методы, которые не являются такими задачами:
Не стесняйтесь просматривать исходный код класса Task здесь .
источник
Async / Await
На самом деле Async / Await - это пара ключевых слов, которые являются просто синтаксическим сахаром для создания обратного вызова асинхронной задачи.
Возьмем для примера эту операцию:
Код выше имеет несколько недостатков. Ошибки не передаются и их трудно прочитать. Но Async и Await приходят, чтобы помочь нам:
Ожидать вызовы должны быть в асинхронных методах. Это имеет некоторые преимущества:
ПРИМЕЧАНИЕ . Async и Await используются с асинхронными вызовами, чтобы этого не делать. Для этого вы должны использовать Task Libary , например Task.Run ().
Вот сравнение между ожидающими и никого не ожидающими решениями
Это не асинхронное решение:
Это асинхронный метод:
На самом деле вы можете вызвать асинхронный метод без ключевого слова await, но это означает, что любое исключение здесь проглатывается в режиме выпуска:
Async и Await не предназначены для параллельных вычислений. Они используются, чтобы не блокировать ваш основной поток. Когда речь идет о приложениях asp.net или Windows, блокировка основного потока из-за сетевого вызова - это плохо. Если вы сделаете это, ваше приложение перестанет отвечать или даже зависнет.
Проверьте MS Docs для большего количества примеров.
источник
Если честно, я все еще думаю, что лучшее объяснение - это будущее и обещания в Википедии: http://en.wikipedia.org/wiki/Futures_and_promises.
Основная идея заключается в том, что у вас есть отдельный пул потоков, которые выполняют задачи асинхронно. При его использовании. Однако объект обещает, что когда-нибудь выполнит операцию и даст вам результат, когда вы ее запросите. Это означает, что он блокируется, когда вы запрашиваете результат и еще не закончил, но в противном случае выполняется в пуле потоков.
Оттуда вы можете оптимизировать вещи: некоторые операции могут быть реализованы асинхронно, и вы можете оптимизировать такие вещи, как файловый ввод-вывод и сетевое взаимодействие, объединяя последующие запросы и / или переупорядочивая их. Я не уверен, что это уже входит в структуру задач Microsoft - но если это не так, я бы добавил это одним из первых.
На самом деле вы можете реализовать будущую модель с помощью выходов в C # 4.0. Если вы хотите знать, как это работает, я могу порекомендовать вам эту ссылку, которая делает достойную работу: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/ . Однако, если вы начнете играть с ним самостоятельно, вы заметите, что вам действительно нужна языковая поддержка, если вы хотите делать все классные вещи - это именно то, что сделала Microsoft.
источник
Посмотрите эту скрипту https://dotnetfiddle.net/VhZdLU (и улучшите ее, если это возможно) для запуска простого консольного приложения, которое показывает использование Task, Task.WaitAll (), async и await. операторов в одной и той же программе.
Эта скрипка должна очистить вашу концепцию цикла выполнения.
Вот пример кода
Трассировка из окна вывода:
источник
источник
На более высоком уровне:
1) Ключевое слово Async включает ожидание, и это все, что он делает. Ключевое слово Async не запускает метод в отдельном потоке. Начальный асинхронный метод выполняется синхронно до тех пор, пока не достигнет ожидающего выполнения задачи, занимающей много времени.
2) Вы можете ожидать метода, который возвращает Task или Task типа T. Вы не можете ожидать метода async void.
3) В тот момент, когда основной поток встречается, ожидает выполнения трудоемкой задачи или когда фактическая работа начинается, основной поток возвращается к вызывающей стороне текущего метода.
4) Если основной поток видит ожидание для задачи, которая все еще выполняется, он не ждет ее и возвращается к вызывающей стороне текущего метода. Таким образом, приложение остается отзывчивым.
5) Ожидание обработки задачи теперь будет выполняться в отдельном потоке из пула потоков.
6) Когда эта задача ожидания завершена, весь код ниже ее будет выполняться отдельным потоком
Ниже приведен пример кода. Выполните его и проверьте идентификатор потока
источник
Я так понимаю , это также, должен быть третий член добавляется к смеси:
Task
.Async
это просто спецификатор, который вы добавляете в свой метод, чтобы сказать, что это асинхронный метод.Task
является возвращениемasync
функции. Это выполняется асинхронно.Вы
await
Задача. Когда выполнение кода достигает этой строки, управление переходит обратно к вызывающей стороне вашей исходной функции.Если вместо этого вы назначаете возврат
async
функции (то естьTask
) переменной, когда выполнение кода достигает этой строки, оно просто продолжается за этой строкой в окружающей функции, в то время какTask
выполняется асинхронно.источник
Эта статья MDSN: Асинхронное программирование с асинхронным и ожидающим (C #) объясняет это явно:
источник
В следующем коде метод HttpClient GetByteArrayAsync возвращает задачу getContentsTask. Задача - это обещание создать фактический байтовый массив, когда задача будет выполнена. Оператор await применяется к getContentsTask для приостановки выполнения в SumPageSizesAsync до завершения getContentsTask. Тем временем управление возвращается вызывающей стороне SumPageSizesAsync. Когда getContentsTask завершается, выражение await преобразуется в байтовый массив.
источник
Ниже приведен код, который читает файл Excel, открывая диалоговое окно, а затем использует асинхронное ожидание для запуска асинхронного кода, который читает одну строку из Excel и привязывается к сетке.
источник
Ответы здесь полезны в качестве общего руководства по await / async. Они также содержат некоторые подробности о том, как await / async подключен. Я хотел бы поделиться с вами некоторым практическим опытом, который вы должны знать, прежде чем использовать этот шаблон проектирования.
Термин «ожидание» является буквальным, поэтому любой поток, к которому вы его вызываете, будет ожидать результата метода, прежде чем продолжить. На переднем плане , это катастрофа . Поток переднего плана несет бремя создания вашего приложения, включая представления, модели представлений, начальные анимации и все остальное, что вы загрузили с этими элементами. Поэтому, когда вы ожидаете потока переднего плана, вы останавливаете приложение. Пользователь ждет и ждет, когда ничего не происходит. Это обеспечивает отрицательный пользовательский опыт.
Вы, конечно, можете ожидать фоновый поток, используя различные средства:
Полный код этих замечаний находится по адресу https://github.com/marcusts/xamarin-forms-annoyances . Смотрите решение под названием AwaitAsyncAntipattern.sln.
На сайте GitHub также есть ссылки на более подробное обсуждение этой темы.
источник
async / await
это синтаксический сахар для обратных вызовов, он не имеет ничего общего с потоками. msdn.microsoft.com/en-us/magazine/hh456401.aspx Он предназначен для кода без привязки к ЦП, например, ожидание ввода или задержка.Task.Run
должны быть использованы только для CPU связанного кода blog.stephencleary.com/2013/10/...The term "await" is literal, so whatever thread you call it on will wait for the result of the method before continuing.
Это не правда - может быть, вы имели в виду Task.Wait ()? Когда вы используетеawait
, он устанавливает остальную часть метода как продолжение, которое будет выполнено, когда все, что вы ожидаете, будет завершено. Он выходит из метода, в котором вы его использовали, чтобы вызывающий мог продолжить. Затем, когда ожидаемая строка фактически завершена, она завершает остаток этого метода в каком-то потоке (обычно рабочем потоке).async/await
посвящен освобождению потоков .NET. Когда выawait
выполняете действительно асинхронную операцию (такую как .NET File.WriteAsync), она приостанавливает оставшуюся часть метода, который вы использовалиawait
, чтобы вызывающая сторона могла продолжить и потенциально завершить свое назначение. Нет потоковой блокировки или ожиданияawait
операции -ed. Когда операция, которую выawait
редактировали, завершена, оставшаяся частьasync/await
метода помещается в поток и выполняется (аналогично идее обратного вызова).