+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 91.82 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

C# 5 - об async/await с начала

15.03.2012 16:36

В недавно вышедшей Visual Studio 11 Beta встроена новая и главная фишка будущего C# 5 - асинхронное программирование с помощью async/await. Про нее уже написано достаточно много статей в том, числе на хабре - например, эта серия статей. Однако, я для себя так и не понял в чем суть нового синтаксиса, пока сам не попробовал его в деле. Данная статья - попытка самому структурировать и до конца разобраться с этим достаточно интересным инструментом и поделиться результатами с сообществом, рассказав про него немного иначе. Итак, поехали…

Зачем это нужно?

 C# активно развивающийся язык в каждой версии которого появляются интересные особенности, которые действительно упрощают написание качественного и понятного кода. Например, Linq значительно упростил написание фильтров для коллекций и sql-запросов в коде. Сейчас дошла очередь до асинхронности.

 И хотя во фреймворке уже накопилось достаточно большое количество способов написания многопоточного кода, от ручного создания потока до визуального компонента BackgroundWorker, разработка асинхронного приложения требует написания приличного объема инфраструктурного кода, который увеличивается по мере усложнения задачи. Главной проблемой этого, на мой взгляд, является необходимость изменения состояния пользовательского интерфейса из фонового потока (чего, как известно, нельзя делать напрямую).

 Новая языковая конструкция async/await решает эту проблему, позволяя не только запускать задачу в фоновом потоке и при ее завершении выполнить код в основном, но и делает это наглядно - код выглядит почти как синхронный (включая обработку исключений).

Встречаем: async/await

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

// Синхронная версия
private void OnButtonClick()
{
   TextBox.Text = new WebClient().DownloadString("http://habrahabr.ru/"); 
}

// Асинхронная версия
private async void OnButtonClick()
{
   TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://habrahabr.ru/");
}

 И если в синхронном варианте все просто и понятно, то с асинхронным возникает много вопросов. Начнем как ни странно с нового метода у класса WebClient - DownloadStringTaskAsync - этот метод возвращает Task<string> и в новой студии отмечается как awaitable. Тип возвращаемого значения ключевой момент во всей этой истории - забегая вперед стоит сказать, что await умеет работать только с функциями возвращающими Task и Task<T>.
UPD: как справедливо заметил jack128 в комментариях, await работает с любым объектом, у которого есть метод GetAwaiter(), спасибо ему за корректировку.

 Итак, метод DownloadStringTaskAsync создает задачу Task и сразу возвращает ее из функции, в то время как в фоновом потоке начинает скачиваться страница с запрошенного url. Мы вольны работать непосредственно с объектом Task вручную дождавшись выполнения результата:

private void OnButtonClick()
{
  Task<string> task = new WebClient().DownloadStringTaskAsync("http://microsoft.com/");
  task.Wait(); // Здесь мы ждем завершения задачи, что блокирует поток
  TextBox.Text = task.Result;
}

 Данный код разумеется остается синхронным, так как мы в основном потоке ждем выполнения фонового…

 Нужен способ как удобно и асинхронно работать с задачей (Task<T>), которая осталась единственной "ниточкой", которая связывает нас с фоновым потоком. И здесь на сцене появляется await - он не только разворачивает Task<T> в T, но и устанавливает остаток метода в "продолжение" (continuation), которое выполнится после завершения задачи и самое главное в том же потоке. При этом произойдет выход из функции OnButtonClick() и приложение продолжит работать в штатном режиме - реагируя на действия пользователей.

 Как только фоновый поток завершит работу и вернет результат - будет выполнено "продолжение" в основном потоке, которое в данном случае установит содержимое страницы в текстовое поле.

 Осталось разобраться с ключевым словом async - им необходимо, помечать те функции в которых будет использоваться await. Все просто, а главное компилятор присмотрит, чтобы вы не забыли про это - не дав скомпилировать программу.

Как это выглядит в действии

 В функции может быть несколько await'ов, что позволяет создавать асинхронные цепочки выполнения:

private async void StartButtonClick(object sender, RoutedEventArgs e)
{
   // Убираем возможность повторного нажатия на кнопку
   StartButton.IsEnabled = false;

   // Вызываем новую задачу, на этом выполнение функции закончится
   // а остаток функции установится в продолжение
   TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://habrahabr.ru/");
   StatusLabel.Content = "Загрузка страницы завершена, начинается обработка";

   // В продолжении можно также запускать асинхронные операции со своим продолжением
   var result = await Task<string>.Factory.StartNew(() =>
   {       
     Thread.Sleep(5000); // Имитация длительной обработки...
     return "Результат обработки";
   });

   // Продолжение второй асинхронной операции
   StatusLabel.Content = result;
   StartButton.IsEnabled = true;
}

 А что на счет исключений? Раз уж разработчики пообещали, что новый синтаксис будет простым и близким к синхронному, они не могли обойти стороной такую важную проблему обработки исключений. Как и обещалось, исключения брошенные в фоновом потоке, можно обработать используя классический синтаксис (как будто никакой асинхронности и нет):

private async void StartButtonClick(object sender, RoutedEventArgs e)
{
   try
   {
     TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://not-habrahabr.ru/");
   }
   catch (Exception ex)
   {
     MessageBox.Show(ex.Message);
   }
}

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

// Это не работает!!!
private void StartButtonClick(object sender, RoutedEventArgs e)
{
   try
   {    
     Download();    
   }
   catch (Exception ex)
   {
     MessageBox.Show(ex.Message);
   }
}

private async void Download()
{
   TextBox.Text = await new WebClient().DownloadStringTaskAsync("http://not-habrahabr.ru/");
}

 Функция Download вернет управление как только будет создан Task с фоновым потоком, а после этого будет выполнен и выход из функции StartButtonClick… и уже позже в фоновом потоке будет сгенерировано исключение о том, что не удается разрешить доменное имя. Более подробное объяснение можно почитать здесь.

Итого

 В грядущем .Net 4.5 многие классы, будет дополнены для поддержки нового синтаксиса - т.е. появится много функций возвращающих Task и Task<T>. И судя по простоте нового синтаксиса он получит большое распространение, поэтому необходимо ясное понимание новых конструкций языка, их действия и области применения.

 Подытожим - ключевое слово async не приводит к тому, что метод будет выполняться в фоновом потоке (как кажется из названия), а только отмечает, что внутри метода присутствует await, который работает с Task и Task<T> таким образом, что остаток метода после await будет выполнен после завершения Task, но в основном потоке.

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

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года