async + await == синхронизация?

24

Наткнулся на этот пост, в котором говорится о создании асинхронных веб-запросов.

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

Mrchief
источник
5
Не совсем. Ваш код является синхронным в том смысле, что ничего не происходит, пока вы не получите результат. Однако ниже вы, вероятно, отказались от потока, в котором работали, до тех пор, пока не вернется асинхронный метод, а затем получили другой поток для продолжения выполнения.
R0MANARMY
2
но с помощью async вы можете одновременно выполнить еще одну асинхронную операцию и затем ждать 2, с синхронизацией это невозможно
ratchet freak
Вот статья ( tomasp.net/blog/async-compilation-internals.aspx ), в которой обсуждаются некоторые аспекты асинхронности в C # - это часть серии, посвященной асинхронному программированию в C # и F #.
Павел
@ratchetfreak: Да, само собой разумеется, если вы делаете несколько звонков.
Mrchief
@ R0MANARMY: Если ваше приложение делает что-то другое, тогда yes и async + await это позволяют. Аким говорит это лучше всего! Но представьте, что код не находится в обработчике button_click или в любом другом обработчике событий в этом отношении. Если кто-то слепо копирует код (async + await lines) в любой метод, это может создать ложное впечатление, что ваш код асинхронный, но фактически этого не происходит.
Mrchief

Ответы:

32

Нет, async + await != syncиз-за продолжения

Из MSDN «Асинхронное программирование с использованием асинхронных и ожидающих (C # и Visual Basic)»

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

Например, асинхронное выполнение не заблокирует поток пользовательского интерфейса и Some TextBox.Textбудет обновлено после завершения загрузки.

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}
Аким
источник
Очень красиво сказано!
Mrchief
Не могли бы вы объяснить более подробно. Вы говорите ... что без этого ... вы не сможете взаимодействовать с пользовательским интерфейсом ... как это было бы в главном потоке. Значит ли это, что это станет применимо только в программе типа приложения, применяемой к вебу, где взаимодействие отделено от потока веб-сервера. Таким образом, в скорлупе орехов это становится важным, то есть не синхронизируется *, когда ваш основной поток является запущенным потоком. Не приведет ли это к неожиданному поведению, то есть в приложении (1 основной поток) нажаты две кнопки ... но вы должны иметь возможность нажимать 1 без первого завершения?
Seabizkit
Как насчет Console.WriteLine(await GetStringOverNetwork());? Что если вам нужен вывод асинхронного вызова? Будет ли программа блокироваться при первом доступе, даже если поток потенциально может продолжить выполнение?
Андрей
6

Нет, это не то же самое.

Ваш asyncблок кода ожидает awaitвозврата вызова, чтобы продолжить, однако остальная часть вашего приложения не ждет и все еще может продолжаться как обычно.

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

Рейчел
источник
нельзя ли синхронизировать вызов как async + await?
чокнутый урод
@ratchetfreak Я думаю, что есть некоторые накладные расходы на настройку await / async, поэтому я не думаю, что вы захотите кодировать все приложение с ним. Я использую его только для выполнения потенциально долго работающих блоков кода, чтобы он не блокировал мои приложения. :)
Рейчел
5

Пожалуйста, позвольте мне прояснить вещи в отношении async / await.

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

Следовательно, асинхронный блок не блокируется и не ожидает завершения ожидаемого вызова; Управление возвращается немедленно, когда встречается команда await.

Базовый конечный автомат является частью "магии" использования асинхронного / ожидающего, который не используется и не пропущен.

Седрик Харрис
источник
2

Я наткнулся на это, имея в виду тот же вопрос, но после прочтения ответов вопрос, кажется, задерживается, смущенный ссылками на «магию под капотом».

Из вышеупомянутого асинхронного программирования :

  • asyncКлючевое слово превращает метод в качестве метода асинхронного, что позволяет использовать awaitключевое слово в своем теле.
  • Когда awaitключевое слово применяется, оно приостанавливает вызывающий метод и возвращает управление своему вызывающему, пока ожидаемая задача не будет завершена.
  • awaitможет использоваться только внутри asyncметода.

Блокируется ли контекст, с которым вы сталкиваетесь await?

  • Да . По сути, это локальный барьер синхронизации для поддержания известного состояния в контексте выполнения; за исключением того, что другие контексты, если таковые имеются, не объединены.

Остальная часть приложения блокируется на await?

  • Это зависит от того, как написано ваше заявление. Если это серия зависимых awaitзадач ed, запущенных последовательно в одном и том же контексте (см. « Попытка понять некоторое поведение асинхронности / ожидания» )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

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

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

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    В общем случае awaitприводит к выполнению внешнего контекста, из которого вызывается текущий контекст. Однако, если внешний контекст сам ожидает ток, он похож на последовательные awaits в том же контексте.

Таким образом, чтобы воспользоваться asyncпреимуществами, необходимо спроектировать приложение для запуска нескольких параллельных контекстов (пользовательский интерфейс, клиент данных и т. Д.), А затем awaitв одном контексте выполнить выполнение в других контекстах, чтобы все приложение не блокировалось для отдельного человека await.

oversynched
источник