SlideShare uma empresa Scribd logo
1 de 74
Асинхронное
программирование в .Net
Сергей Тепляков
STeplyakov@luxoft.com
О Вашем инструкторе


 Сергей Тепляков
 Visual C# MVP, RSDN Team member
 Sergey.Teplyakov@gmail.com
 SergeyTeplyakov.blogspot.com




                                    1-2
Цели курса…
Слушатели изучат:
 Достоинства и недостатки
  синхронного программирования
 Существующие паттерны
  асинхронного программирования на
  платформе .Net
 Использование библиотеки
  PowerThreading
 Использование библиотеки TPL
 Новые возможности C# 5
                                     1-3
Необходимая подготовка
Слушатели должны:

 Быть знакомы с основами языка C#
  и платформы .Net
 Обладать базовыми знаниями
  многопоточности




                                     1-4
Roadmap

 Модель синхронного
  программирования
 Паттерны асинхронного
  программирования на платформе .Net
 Недостатки существующих моделей
 Библиотека PowerThreading
 Библиотека TPL
 C# 5.0: async и await
                                       1-5
Недостатки синхронного
программирования

 Плохая масштабируемость
 Блокирование пользовательского
  интерфейса
 Низкая эффективность операций
  ввода/вывода
 Невозможность использования в
  некоторых контекстах (например, с
  JavaScript и Silverlight)
Плохая масштабируемость.
последовательное выполнение
       sd Sync


                 Client                              HttpWebRequest




                          webRequest1.GetWebResponce()




                             ProcessWebResponce1()



                          webRequest2.GetWebResponce()




                             ProcessWebResponce2()
Плохая масштабируемость

 Неэффективное использование
  мощностей современных многоядерных
  процессоров для CPU-Bound операций
 Неэффективное выполнение IO-Bound
  операций даже для одноядерных
  процессоров
Блокировка пользовательского
интерфейса
Блокировка пользовательского
интерфейса

// Обработчик кнопки получения данных от веб-страниц
private void receiveDataButton_Click(object sender, EventArgs e)
{
    Stopwatch sw = Stopwatch.StartNew();    // 1
    _summaryContentLength = 0;              // 2
    foreach (var url in urls)
    {
        // GetResponse возвращает результат синхронно
        using (WebResponse webResponse = GetResponse(url)) // 3
        {
            ProcessResponse(webResponse);   // 4
            executionTimeTextBox.Text = sw.ElapsedMilliseconds.ToString();
        }
    }
}
А ведь это и не всегда
возможно!

 Некоторые среды, такие как Silverlight и
  JavaScript не поддерживают синхронные
  операции
Рассматриваемые темы

 Модель синхронного программирования
 Паттерны асинхронного
  программирования на платформе
  .Net
 Недостатки существующих моделей
 Библиотека PowerThreading
 Библиотека TPL
 C# 5.0: async и await
Асинхронная модель
программирования

 Два паттерна асинхронного
  программирования
   Classical Async Pattern
   Event-Based Async Pattern
Classical Async Pattern

 Структура паттерна:
// Синхронный метод
public <return> Operation(<parameters>, <out params> )

// Методы классического асинхронного паттерна
public IAsyncResult BeginOperation(<parameters>, AsyncCallback callback,
   object state)
public <return> EndOperation(IAsyncResult asyncResult, <out paramss>)


 Пример:
public WebResponse GetWebResponse(string url, out TimeSpan duration);
public IAsyncResult BeginGetWebResponse(string ulr, object state);
public WebResponse EndGetWebResponse(IAsyncResult ar, out TimeSpan duration);
Classical Async Pattern

 Метод BeginXXX инициирует асинхронную
  операцию
 Метод BeginXXX возвращает IAsyncResult,
  который является маркером асинхронной
  операции
 AsyncCallback представляет собой
  функцию, которая будет вызвана при
  завершении операции
 State представляет собой любой
  пользовательский объект
Classical Async Pattern

 Все by-value и by-ref параметры
  синхронного метода становятся by-value
  параметрами BeginXXX метода
 Тип возвращаемого значения синхронного
  метода совпадает с типом возвращаемого
  значения EndXXX метода
 ref и out параметры синхронного метода
  добавляются в EndXXX метод
 Исключения, генерируемые синхронным
  методом, генерируются методом EndXXX
Примеры Classical Async
Pattern

 Класс System.IO.Stream
public int Read(byte[] buffer, int offset, int count)
public IAsyncResult BeginRead(byte[] buffer, int offset, int count,
    AsyncCallback callback, object state)
public int EndRead(IAsyncResult asyncResult)


 Класс System.Net.WebRequest
public WebResponse GetWebResponse();
public IAsyncResult BeginGetWebResponse(AsyncCallback callback, object state);
public WebResponse EndGetResponse(IAsyncResult asyncResult);
Асинхронное выполнение
sd ClassicAsync


         Form                          Client                             HttpWebRequest         IO completion




                                                webRequest1.BeginGetResponse()


                                                webRequest2.BeginGetResponse()




                                                                 webRequest2.ProcessResponse()




                                                      ProcessResponse()
                  UpdateUIElements()


                                                                 webRequest1.ProcessResponse()



                                                      ProcessResponse()

                  UpdateUIElements()
Classical Async Pattern

 В обработчике UI события:
   Проинициализировать дополнительные поля (теперь без них
    не обойтись)
   Сделать неактивной кнопку
   В цикле начать все операции асинхронно (вызывать метод
    BeginGetResponse)
Classical Async Pattern

 В обработчике завершения асинхронной
  операции:
   Получить WebResponse (вызывать метод EndGetReponse)
   Обработать ответ, не забывая, что обработка происходит не
    в потоке UI
   Понять, что все асинхронные операции завершены (??)
    (посчитать количество завершенных операций)
   Сделать активной кнопку, если все операции таки
    завершены
   Если перед началом выполнения асинхронных операций
    были выделены ресурсы, то освободить их вручную
Разница синхронного и
асинхронного вариантов для
трех веб-узлов
 Среднее выполнение синхронного
  варианта: 520мс
 Среднее выполнение асинхронного
  варианта: 280 мс
 Количество строк кода в синхронном
  решении: 20
 Количество строк кода в асинхронном
  решении: 78
Event-Based Async Pattern
Event-Based Async Pattern
class Class Model


   AsyncCompletedEv entArgs
                                 Находится в пространстве
    +   Canceled: bool           имен: System.ComponentModel                   Событие MethodCompleted
    +   Error: Exception                                                       вызывается как при успешном,
    +   UserState: object                                                      так и при неудачном завершении
                                                                               метода.

                                                                               Метод CancelMethod и событие
                                                                               ProgressChanged являются
                                                                               опциональными.
    MethodCompletedEv entArgs
                                                     SomeType
                                Uses
    +   Arg1: int
                                         +   event MethodCompleted
    +   Arg2: string
                                         +   event ProgressChanged
    +   Result: MethodResult
                                         +   CancelMethod() : void
                Uses
                                         +   MethodAsync(string, int) : void



           MethodResult
Event-Based Async Pattern

 MethodAsync инициирует асинхронную
  операцию
 Есть только одно событие
  MethodCompleted, EventArgs которого
  содержат Result, Error, IsCanceled
 Возможна, но не обязательна,
  поддержка отмены и прогресса
  выполнения
Event-Based Async Pattern

 By-value и ref параметры синхронного
  метода являются входными
  параметрами метода MethodAsync
 Ref и out-параметры становятся
  readonly полями
  MethodCompletedEventArgs
 Событие MethodCompleted
  вызывается в «правильном»
  потоке (в потоке UI для WinForms
  или WPF)
Event-Based Async Pattern

// Функция обработки принятых данных
private void receiveDataButton_Click(object sender, EventArgs e)
{
    // Подготовка операции (отключение кнопки «Принять»,
    // инициализация счетчиков и т.д.
    foreach (var url in urls)
    {
        var webClient = new WebClient();
        webClient.DownloadDataAsync(new Uri(url));

        webClient.DownloadDataCompleted +=
            (s, ev) =>
            {
                // Для обработки ошибки в этом случае нужно
                // обратиться к ствойству ev.Error.
                // Обработка результатов
            };
    }
}
Да как же между ними
выбрать?

 Классический паттерн более
  низкоуровневый и более гибкий
 Event-Based паттерн более простой в
  применении, в частности с UI
  дизайнерами
 Классический паттерн – для кода
  общего назначения, Event-Based – для
  компонентов
 Не применяйте оба паттерна для одного
  класса
Рассматриваемые темы

 Модель синхронного программирования
 Паттерны асинхронного
  программирования на платформе .Net
 Недостатки существующих
  моделей
 Библиотека PowerThreading
 Библиотека TPL
 C# 5.0: async и await
Недостатки моделей
асинхронного программирования

 Непонятный поток исполнения (Control
  Flow)
 Сложность чтения кода и его
  сопровождения
 Сложность обработки ошибок
 Невозможность использования
  привычных языковых конструкций
  (using, try/finally etc)
Рассматриваемые темы

 Модель синхронного программирования
 Паттерны асинхронного
  программирования на платформе .Net
 Недостатки существующих моделей
 Библиотека PowerThreading
 Библиотека TPL
 C# 5.0: async и await
PowerThreading Library

 Разработана Джеффри Рихтер и
  компанией Wintellect
 Содержит класс AsyncEnumerator для
  упрощения работы с асинхронными
  операциями
 Содержит вспомогательные классы для
  работы с многопоточностью (ResourceLock,
  ReaderWriterGate etc)
 Другие вспомогательные классы (Disposer,
  Exception<T>, Singleton etc)
Класс AsyncEnumerator.
Основные концепции

 Поддерживает гибкое управление
  асинхронными операциями (отмену,
  таймауты и т.п.)
 Использует преимущество блока
  итераторов (Iterator block) для
  упрощения потока исполнения
 Использует SynchronizationContext для
  маршалинга потока выполнения в поток
  UI
Класс AsyncEnumerator.
Простой пример
static IEnumerator<int> WorkerMethod()
{
    // Инициируем n асинхронных операций,
    // вызываем BeginRead, BeginGetWebResponse, BeginExecuteCommand etc

   // "возвращаем" n, что говорит AsyncEnumerator-у
   // о количестве запущенных асинхронных операций
   yield return n;

   //   класс AsyncEnumerator вызовет в следующий раз
   //   метод MoveNext нашего енумератора (и мы здесь получим управление)
   //   только после завершения указанного количества асинхронных операций.
   //   Причем, если экземпляр класса AsyncEnumerator-а создавался
   //   с контекстом синхронизации (например, он создавался в потоке UI)
   //   то метод MoveNext будет вызван в потоке UI!

   // Начинаем еще несколько асинхронных операций (например, k)
   yield return k;

}
// Создаем экземпляр енумератора
AsyncEnumerator ae = new AsyncEnumerator();
// Запускаем асинхронные операции, всю грязную работу
// берет на себя AsyncEnumerator
ae.BeginExecute(WorkerMethod(), ae.EndExecute);
Отступление от темы. Блоки
итераторов
static IEnumerator<int> GetNumbers()
{
    string padding = "tt";
    Console.WriteLine(padding + "Первая строка метода GetNumbers()");
    Console.WriteLine(padding + "Сразу перед yield return 7");
    yield return 7;
    Console.WriteLine(padding + "Сразу после yield return 7");
    Console.WriteLine(padding + "Сразу перед yield return 42");
    yield return 42;
    Console.WriteLine(padding + "Сразу после yield return 42");
}
Визуализация итераторов
                                             static IEnumerator<int> GetNumbers()
WriteLine("Вызываем GetNumbers()");          {
IEnumerator<int> iterator = GetNumbers();        string padding = "tt";
                                                 Console.WriteLine(padding + "Первая строка метода GetNumbers()"); // 1
WriteLine("Вызываем MoveNext()...");             Console.WriteLine(padding + "Сразу перед yield return 7"); // 2
bool more = iterator.MoveNext();                 yield return 7; // 3
WriteLine("Result=...", iterator.Current);       Console.WriteLine(padding + "Сразу после yield return 7"); // 4
                                                 Console.WriteLine(padding + "Сразу перед yield return 42"); // 5
WriteLine("Снова вызываем MoveNext()...");       yield return 42; // 6
more = iterator.MoveNext();                      Console.WriteLine(padding + "Сразу после yield return 42"); //7
WriteLine("Result=...", iterator.Current);   }


WriteLine("Снова вызываем MoveNext()...");
more = iterator.MoveNext();
WriteLine("Result={0} (stopping)", more);


Результат:
Вызываем GetNumbers()
Визуализация итераторов
                                               static IEnumerator<int> GetNumbers()
WriteLine("Вызываем GetNumbers()");            {
IEnumerator<int> iterator = GetNumbers();            string padding = "tt";
                                                     Console.WriteLine(padding + "Первая строка метода GetNumbers()");
WriteLine("Вызываем MoveNext()...");                 Console.WriteLine(padding + "Сразу перед yield return 7");
bool more = iterator.MoveNext();                     yield return 7;
WriteLine("Result=...", iterator.Current);           Console.WriteLine(padding + "Сразу после yield return 7");
                                                     Console.WriteLine(padding + "Сразу перед yield return 42");
WriteLine("Снова вызываем MoveNext()...");           yield return 42; // 6
more = iterator.MoveNext();                          Console.WriteLine(padding + "Сразу после yield return 42");
WriteLine("Result=...", iterator.Current);     }

WriteLine("Снова вызываем MoveNext()...");
more = iterator.MoveNext();
WriteLine("Result={0} (stopping)", more);


Результат:
Вызываем GetNumbers()
Вызываем MoveNext()...
                 Первая строка метода GetNumbers()
                 Сразу перед yield return 7
Result=True; Current=7
Визуализация итераторов
                                               static IEnumerator<int> GetNumbers()
WriteLine("Вызываем GetNumbers()");            {
IEnumerator<int> iterator = GetNumbers();          string padding = "tt";
                                                   Console.WriteLine(padding + "Первая строка метода GetNumbers()");
WriteLine("Вызываем MoveNext()...");               Console.WriteLine(padding + "Сразу перед yield return 7");
bool more = iterator.MoveNext();                   yield return 7;
WriteLine("Result=...", iterator.Current);          Console.WriteLine(padding + "Сразу после yield return 7");
                                                    Console.WriteLine(padding + "Сразу перед yield return 42");
WriteLine("Снова вызываем MoveNext()...");          yield return 42;
more = iterator.MoveNext();                         Console.WriteLine(padding + "Сразу после yield return 42");
WriteLine("Result=...“, iterator.Current);     }

WriteLine("Снова вызываем MoveNext()...");
more = iterator.MoveNext();
WriteLine("Result={0} (stopping)", more);


Результат:
Вызываем GetNumbers()
Вызываем MoveNext()...
                Первая строка метода GetNumbers()
                Сразу перед yield return 7
Result=True; Current=7
Снова вызываем MoveNext()...
                 Сразу после yield return 7
                 Сразу перед yield return 42
Result=True; Current=42
Визуализация итераторов
                                              static IEnumerator<int> GetNumbers()
WriteLine("Вызываем GetNumbers()");           {
IEnumerator<int> iterator = GetNumbers();         string padding = "tt";
                                                  Console.WriteLine(padding + "Первая строка метода GetNumbers()");
WriteLine("Вызываем MoveNext()...");              Console.WriteLine(padding + "Сразу перед yield return 7");
bool more = iterator.MoveNext();                  yield return 7;
WriteLine("Result=...", iterator.Current);        Console.WriteLine(padding + "Сразу после yield return 7");
                                                  Console.WriteLine(padding + "Сразу перед yield return 42");
WriteLine("Снова вызываем MoveNext()...");        yield return 42;
more = iterator.MoveNext();                         Console.WriteLine(padding + "Сразу после yield return 42");
WriteLine("Result=...", iterator.Current);    }

WriteLine("Снова вызываем MoveNext()...");
more = iterator.MoveNext();
WriteLine("Result={0} (stopping)", more);


Результат:
Вызываем GetNumbers()
Вызываем MoveNext()...
                Первая строка метода GetNumbers()
                Сразу перед yield return 7
Result=True; Current=7
Снова вызываем MoveNext()...
                Сразу после yield return 7
                Сразу перед yield return 42
Result=True; Current=42
Result=False (stopping)
AsyncEnumerator. Участники

 Класс AsyncEnumerator
 Рабочий метод, возвращающий
  IEnumerator<int>
 Кто-то, связывающий все это
  воедино
AsyncEnumerator
sd AsyncEnumerator


   AsyncEnumerator                           WorkerMethod                             WebRequest   IO Completion




                     calling to MoveNext()


                                                       webRequest1.BeginGetResponse()
                Первый вызов MoveNext
                енумератора
                инициирует
                ас инхронные операции.                 webRequest2.BeginGetResponse()


                                                        WebRequest2Complete()



                                                        WebRequest1Complete()


                          calling to
                          MoveNext()




            Т еперь рабочий метод                      В качес тве метода обработки
            (WorkerMethod) может обработать            завершения ас инхронной
            завершенные операции и начать              операции передаетс я метод
            новые ас инхронные операции.               клас с а AsyncEnumerator-а.
Пример использования класса
AsyncEnumerator
private IEnumerator<int> GetWebData(AsyncEnumerator enumerator)
{
    // Начинаем несколько асинхронных операций
    WebRequest webRequest1 = WebRequest.Create(url1);
    webRequest1.BeginGetResponse(enumerator.End(), null);

    WebRequest webRequest2 = WebRequest.Create(url2);
    webRequest2.BeginGetResponse(enumerator.End(), null);

    yield return 2; // 2 - это количество асинхронных операций

    // Сюда мы попадем уже тогда, когда все асинхронные операции завершены
    WebResponse webResponse1 = webRequest1.EndGetResponse(enumerator.DequeueAsyncResult());
    WebResponse webResponse2 = webRequest2.EndGetResponse(enumerator.DequeueAsyncResult());

    // Обрабатываем полученные результаты аналогичным образом
}
Пример использования класса
AsyncEnumerator
private void receiveDataButton_Click(object sender, EventArgs e)
{
    asyncEnumerator = new AsyncEnumerator();
    // AsyncEnumerator автоматически запоминает контекст синхронизации

    // Запускаем процесс получения данных асинхронно
    asyncEnumerator.BeginExecute(GetWebData(asyncEnumerator),
             asyncEnumerator.EndExecute);
}
Рассматриваемые темы

 Модель синхронного программирования
 Паттерны асинхронного
  программирования на платформе .Net
 Недостатки существующих моделей
 Библиотека PowerThreading
 Библиотека TPL
 C# 5.0: async и await
Библиотека TPL

 Параллелизм задач
 Класс Parallel (Parallel.ForEach etc)
 Parallel LINQ (a.k.a. PLINQ)
Ключевые классы

 Task – инкапсулирует единицу работы
 Task<TResult> - единица работы с определенным
  типом результата
 TaskFactory, TaskFactory<TResult> – фабрики
  создания задач
 TaskScheduler – управляет «расписанием» запуска
  задач
 TaskCompletionSource – управляет «временем жизни»
  задачи
Класс Task<T>

 Представляет собой «незавершенную
  операцию» или «единицу работы»
 Это может быть операция ввода/вывода,
  операция в фоновом потоке, в выделенном
  потоке и т.д.
 Поддерживает «продолжения» с помощью
  ContinueWith
var task2 = task1.ContinueWith(t => … t.Result …);

 Содержит ряд вспомогательных методов:
  WhenAll, WhenAny etc
Примеры использования

1. Простая задача
Task.Factory.StartNew(() => Console.WriteLine("Hello from a task!"));

2. Запуск задачи в выделенном потоке
Task task = Task.Factory.StartNew(
  () =>
     {

        Console.WriteLine("Выполняем длительную операцию");
        Thread.Sleep(TimeSpan.FromHours(1));
        Console.WriteLine("Длительная операция завершена");

     }, TaskCreationOptions.LongRunning);
Примеры использования

3. Получение данных от веб-узла
Task<long> task = new Task<long>(() => {
             var webRequest = WebRequest.Create(url);
             using (var webResponse = webRequest.GetResponse())
             {
                  return webResponse.ContentLength;
             }
         }
);
task.Start();
task.Wait();
long result = task.Result;
4. Использование классического асинхронного API
var webRequest = WebRequest.Create(url);
Task<WebResponse> task = Task<WebResponse>.Factory.FromAsync(
    webRequest.BeginGetResponse, webRequest.EndGetResponse, null);
task.Wait();
var response = task.Result;
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 (ничего не происходит, поскольку задача еще не запущена)
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 (все еще ничего не происходит, поскольку первая задача не запущена)
 (первой задаче установлена вторая задача в виде продолжения)
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 (все еще ничего не происходит, поскольку первая задача не запущена)
 (Связке первых двух задач установлена третья задача в виде продолжения)
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 Запускаем первую задачу
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 Запускаем первую задачу
 Ожидаем завершения цепочки задач
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 (Выполняется первая задача)
 Запускаем первую задачу
 Ожидаем завершения цепочки задач
 Task1...
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 (Выполняется вторая задача, поскольку первая уже завершилась)
 Запускаем первую задачу
 Ожидаем завершения цепочки задач
 Task1...
     Task2...
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");

 Вывод:
 (Выполняется третья задача, поскольку первая и вторая уже завершились)
 Запускаем первую задачу
 Ожидаем завершения цепочки задач
 Task1...
     Task2...
          Task3...
Продолжения

Task task1 = new Task(() => Console.WriteLine("Task1..."));
Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));
Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));

// Запускаем цепочку задач
Console.WriteLine("Запускаем первую задачу");
task1.Start();
Console.WriteLine("Ожидаем завершения цепочки задач");
task3.Wait();
Console.WriteLine("Все задачи завершены");


 Вывод:
 (Выполняется третья задача, поскольку первая и вторая уже завершились)
 Запускаем первую задачу
 Ожидаем завершения цепочки задач
 Task1...
     Task2...
          Task3...
 Все задачи завершены
Рассматриваемые темы

 Модель синхронного программирования
 Паттерны асинхронного
  программирования на платформе .Net
 Недостатки существующих моделей
 Библиотека PowerThreading
 Библиотека TPL
 C# 5.0: async и await
Модель асинхронного
программирования в C# 5

 Аналогична синхронной модели
 Построена по тому же принципу, что и
  класс AsyncEnumerator
 Использует Task<T> для асинхронных
  операций
 Никто не знает, когда выйдет C# 5
 Сейчас доступно Async CTP (Community
  Technology Preview)
Модель асинхронного
программирования в C# 5

 Два новых ключевых слова:
   async – указывает, что метод или лямбда-
    выражение является асинхронным
   await – является аналогом yield return и
    возвращает сразу же управление
    вызывающему коду до тех пор, пока
    асинхронная операция не будет завершена
Модель асинхронного
программирования в C# 5
static async Task<long> GetWebResponseContentLength(string url)
{
    var webRequest = WebRequest.Create(url);
    Console.WriteLine("Перед вызовом await-a. Thread Id: {0}",
        Thread.CurrentThread.ManagedThreadId);

    // Начинаем асинхронную операцию
    Task<WebResponse> responseTask = webRequest.GetResponseAsync();

    // Ожидаем получения ответа
    WebResponse webResponse = await responseTask;

    Console.WriteLine("После завершения await-а. Thread Id: {0}",
        Thread.CurrentThread.ManagedThreadId);

    // В этой строке мы уже получили ответ от веб-узла
    // можем обрабатывать результаты. Тип возвращаемого значения
    // должен соответствовать обобщенному параметру класса Task
    return webResponse.ContentLength;
}
Работа простого метода
WriteLine("Начало исполнения. Thread Id: {0}");    static async Task<long> GetWebResponseContentLength(string url)
                                                   {
Task<long> task =                                      var webRequest = WebRequest.Create(url);
     GetWebResponseContentLength(url);                 WriteLine("Перед вызовом await-a. Thread Id: {0}");

// ожидаем завершения асинхронной операции             // Начинаем асинхронную операцию
task.Wait();                                           Task<WebResponse> respTsk = webRequest.GetResponseAsync();

WriteLine("ContentLength: {0}, Thread Id: {1}");       // Ожидаем получения ответа
                                                       WebResponse webResponse = await respTsk;

                                                       WriteLine("После завершения await-а. Thread Id: {0}");
 Результаты:
 Начало исполнения. Thread Id: 10                      return webResponse.ContentLength;
                                                   }
 Перед вызовом await-a. Thread Id: 10
 (Асинхронная операция запущена)
Работа простого метода
WriteLine("Начало исполнения. Thread Id: {0}");    static async Task<long> GetWebResponseContentLength(string url)
                                                   {
Task<long> task =                                      var webRequest = WebRequest.Create(url);
     GetWebResponseContentLength(url);                 WriteLine("Перед вызовом await-a. Thread Id: {0}");

// ожидаем завершения асинхронной операции             // Начинаем асинхронную операцию
task.Wait();                                           Task<WebResponse> respTsk = webRequest.GetResponseAsync();

WriteLine("ContentLength: {0}, Thread Id: {1}");       // Ожидаем получения ответа
                                                       WebResponse webResponse = await respTsk;

                                                       WriteLine("После завершения await-а. Thread Id: {0}");
 Результаты:                                           return webResponse.ContentLength;
 Начало исполнения. Thread Id: 10                  }

 Перед вызовом await-a. Thread Id: 10
 После завершения await-a. Thread Id: 14
 (Эта строка выполнится только после завершения операции)
Работа простого метода
WriteLine("Начало исполнения. Thread Id: {0}");   static async Task<long> GetWebResponseContentLength(string url)
                                                  {
Task<long> task =                                     var webRequest = WebRequest.Create(url);
     GetWebResponseContentLength(url);                WriteLine("Перед вызовом await-a. Thread Id: {0}");

// ожидаем завершения асинхронной операции            // Начинаем асинхронную операцию
task.Wait();                                          Task<WebResponse> respTsk = webRequest.GetResponseAsync();

WriteLine("ContentLength:{0},Thread Id: {1}");        // Ожидаем получения ответа
                                                      WebResponse webResponse = await respTsk;

                                                      WriteLine("После завершения await-а. Thread Id: {0}");
 Результаты:                                          return webResponse.ContentLength;
                                                  }
 Начало исполнения. Thread Id: 10
 Перед вызовом await-a. Thread Id: 10
 После завершения await-a. Thread Id: 14
 ContentLength: 1672, Thread Id: 10
Сравнение с AsyncEnumerator

 IEnumerator<T> -> async Task<T>
 yield return n -> await task
Модель асинхронного
программирования в C# 5

 Асинхронный метод может возвращать
   void – для асинхронных операций типа “fire
    and forget”
   Task – вызывающий код может дождаться
    завершения асинхронной операции,
    которая не возвращает значения
   Task<T> - для асинхронной операции,
    возвращающей T (string для Task<string>
    etc)
Модель асинхронного
программирования C# 5
private async void receiveDataButton_Click(object sender, EventArgs e)
{
    Stopwatch sw = Stopwatch.StartNew();
    receiveDataButton.Enabled = false;

    IEnumerable<Task<WebResponse>> tasks =
        from url in urls
        let webRequest = WebRequest.Create(url)
        select webRequest.GetResponseAsync();

    // Начинаем выполнять все задачи
    WebResponse[] webResponses = await TaskEx.WhenAll(tasks);

    // Теперь мы можем обработать результаты
    long summaryContentLength = webResponses.Sum(s => s.ContentLength);

    executionTimeTextBox.Text = sw.ElapsedMilliseconds.ToString();
    summaryContentLengthTextBox.Text = summaryContentLength.ToString();
    receiveDataButton.Enabled = true;

    foreach(var wr in webResponses)
        wr.Close();
}
Преимущества новой
асинхронной модели

 Простота использования
 Привычный поток исполнения
 Простота обработки ошибок и
  возможность использования
  конструкций using, try/finally etc
try {
    WebResponse[] data = await TaskEx.WhenAll(tasks);
    // Обработка данных
}
catch (WebException we) {
    //Обработка ошибки получения данных
}
Преимущества новой
асинхронной модели

 Построена на основе проверенных
  идиом (Iterator blocks, AsyncEnumerator,
  Reactive Extensions)
 Построена на основе TPL
  (преимущества от ее использования
  можно закладывать уже сейчас)
Что мы изучили?

 Модель синхронного программирования
 Паттерны асинхронного
  программирования на платформе .Net
 Недостатки существующих моделей
 Библиотека PowerThreading
 Библиотека TPL
 C# 5.0: async и await
Дополнительные ссылки

   Visual Studio Asynchronous Programming (http://msdn.microsoft.com/en-
    us/vstudio/async.aspx)
   Асинхронные операции и AsyncEnumerator
    (http://sergeyteplyakov.blogspot.com/2010/10/asyncenumerator.html)
   «Реактивные расширения и асинхронные операции
    (http://sergeyteplyakov.blogspot.com/2010/11/blog-post.html)
   Знакомство с асинхронными операциями в C# 5
    (http://sergeyteplyakov.blogspot.com/2010/12/c-5.html)
   Джефри Рихтер. Упрощение модели асинхронного программирования с
    помощью AsyncEnumerator (http://msdn.microsoft.com/ru-
    ru/magazine/cc546608.aspx)
   Джеффри Рихтер. Дополнительные возможности AsyncEnumerator
    (http://msdn.microsoft.com/ru-ru/magazine/cc721613.aspx)
Дополнительные ссылки

   Итераторы в языке программирования C#
        Часть 1: http://sergeyteplyakov.blogspot.com/2010/06/c-1.html
        Часть 2: http://sergeyteplyakov.blogspot.com/2010/06/c-2.html
        Часть 3: http://sergeyteplyakov.blogspot.com/2010/06/c-3.html
   Eric Lippert. Continuation Passing Style:
    http://blogs.msdn.com/b/ericlippert/archive/tags/continuation+passing+styl
    e/
   Reactive Extensions Official release
    (http://channel9.msdn.com/Blogs/Charles/Announcing-the-Official-Release-
    of-Rx)
Вопросы?

Mais conteúdo relacionado

Mais procurados

C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.Igor Shkulipa
 
Java осень 2014 занятие 3
Java осень 2014 занятие 3Java осень 2014 занятие 3
Java осень 2014 занятие 3Technopark
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммыPlatonov Sergey
 
Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)Ontico
 
Java Core. Lecture# 5. Concurrency.
Java Core. Lecture# 5. Concurrency.Java Core. Lecture# 5. Concurrency.
Java Core. Lecture# 5. Concurrency.Anton Moiseenko
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.Igor Shkulipa
 
JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.Igor Shkulipa
 
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья СтусьПолный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья СтусьMail.ru Group
 
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorFedor Lavrentyev
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5Technopark
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.Igor Shkulipa
 
Java Core. Lecture# 3. Part# 2. Exceptions.
Java Core. Lecture# 3. Part# 2. Exceptions.Java Core. Lecture# 3. Part# 2. Exceptions.
Java Core. Lecture# 3. Part# 2. Exceptions.Anton Moiseenko
 
Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)Ontico
 
C# Desktop. Занятие 16.
C# Desktop. Занятие 16.C# Desktop. Занятие 16.
C# Desktop. Занятие 16.Igor Shkulipa
 
Метапрограммирование с примерами на JavaScript
Метапрограммирование с примерами на JavaScriptМетапрограммирование с примерами на JavaScript
Метапрограммирование с примерами на JavaScriptTimur Shemsedinov
 
RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)Noveo
 
Java. Многопоточность.
Java. Многопоточность.Java. Многопоточность.
Java. Многопоточность.Unguryan Vitaliy
 
Multithreading in java past and actual
Multithreading in java past and actualMultithreading in java past and actual
Multithreading in java past and actualYevgen Levik
 

Mais procurados (20)

C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.C++ STL & Qt. Занятие 10.
C++ STL & Qt. Занятие 10.
 
Java осень 2014 занятие 3
Java осень 2014 занятие 3Java осень 2014 занятие 3
Java осень 2014 занятие 3
 
JavaDay'14
JavaDay'14JavaDay'14
JavaDay'14
 
Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммы
 
Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)Тестируй это / Виктор Русакович (GP Solutions)
Тестируй это / Виктор Русакович (GP Solutions)
 
Java Core. Lecture# 5. Concurrency.
Java Core. Lecture# 5. Concurrency.Java Core. Lecture# 5. Concurrency.
Java Core. Lecture# 5. Concurrency.
 
C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.C++ STL & Qt. Занятие 05.
C++ STL & Qt. Занятие 05.
 
JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.JavaScript Базовый. Занятие 02.
JavaScript Базовый. Занятие 02.
 
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья СтусьПолный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
 
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev FedorProgramming Java - Lection 06 - Multithreading - Lavrentyev Fedor
Programming Java - Lection 06 - Multithreading - Lavrentyev Fedor
 
Java осень 2014 занятие 5
Java осень 2014 занятие 5Java осень 2014 занятие 5
Java осень 2014 занятие 5
 
C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.C++ STL & Qt. Занятие 04.
C++ STL & Qt. Занятие 04.
 
Java Core. Lecture# 3. Part# 2. Exceptions.
Java Core. Lecture# 3. Part# 2. Exceptions.Java Core. Lecture# 3. Part# 2. Exceptions.
Java Core. Lecture# 3. Part# 2. Exceptions.
 
java
javajava
java
 
Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)Особенности разработки API / Всеволод Шмыров (Яндекс)
Особенности разработки API / Всеволод Шмыров (Яндекс)
 
C# Desktop. Занятие 16.
C# Desktop. Занятие 16.C# Desktop. Занятие 16.
C# Desktop. Занятие 16.
 
Метапрограммирование с примерами на JavaScript
Метапрограммирование с примерами на JavaScriptМетапрограммирование с примерами на JavaScript
Метапрограммирование с примерами на JavaScript
 
RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)RxJava+RxAndroid (Lecture 20 – rx java)
RxJava+RxAndroid (Lecture 20 – rx java)
 
Java. Многопоточность.
Java. Многопоточность.Java. Многопоточность.
Java. Многопоточность.
 
Multithreading in java past and actual
Multithreading in java past and actualMultithreading in java past and actual
Multithreading in java past and actual
 

Semelhante a Luxoft async.net

Wild Async .NET world: AID Kit for boy-scouts
Wild Async .NET world: AID Kit for boy-scoutsWild Async .NET world: AID Kit for boy-scouts
Wild Async .NET world: AID Kit for boy-scoutsHYS Enterprise
 
Асинхронные вызовы в .NET
Асинхронные вызовы в .NETАсинхронные вызовы в .NET
Асинхронные вызовы в .NETBonart
 
Async clinic by by Sergey Teplyakov
Async clinic by by Sergey TeplyakovAsync clinic by by Sergey Teplyakov
Async clinic by by Sergey TeplyakovAlex Tumanoff
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1Michael Karpov
 
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)Noveo
 
Киллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/awaitКиллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/awaitByndyusoft
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Sigma Software
 
6 создание распределенных приложений по технологии remoting
6 создание распределенных приложений по технологии remoting6 создание распределенных приложений по технологии remoting
6 создание распределенных приложений по технологии remotingKewpaN
 
Компонентная среда разработки инструментария нагрузочного тестирования
Компонентная среда разработки инструментария нагрузочного тестированияКомпонентная среда разработки инструментария нагрузочного тестирования
Компонентная среда разработки инструментария нагрузочного тестированияSQALab
 
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...Timur Shemsedinov
 
Reactive Extensions
Reactive ExtensionsReactive Extensions
Reactive ExtensionsGetDev.NET
 
анализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестированияанализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестированияRuslan Shevchenko
 
Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Alex Tumanoff
 
Инструментируй это
Инструментируй этоИнструментируй это
Инструментируй этоRoman Dvornov
 
Многопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиМногопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиDotNetConf
 
CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...
CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...
CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...CodeFest
 
вспомогательные алгоритмы
вспомогательные алгоритмывспомогательные алгоритмы
вспомогательные алгоритмыЕлена Ключева
 

Semelhante a Luxoft async.net (20)

Wild Async .NET world: AID Kit for boy-scouts
Wild Async .NET world: AID Kit for boy-scoutsWild Async .NET world: AID Kit for boy-scouts
Wild Async .NET world: AID Kit for boy-scouts
 
Асинхронные вызовы в .NET
Асинхронные вызовы в .NETАсинхронные вызовы в .NET
Асинхронные вызовы в .NET
 
Aspect Oriented Approach
Aspect Oriented ApproachAspect Oriented Approach
Aspect Oriented Approach
 
Async clinic by by Sergey Teplyakov
Async clinic by by Sergey TeplyakovAsync clinic by by Sergey Teplyakov
Async clinic by by Sergey Teplyakov
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
 
Киллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/awaitКиллер-фича языка C# — конструкция async/await
Киллер-фича языка C# — конструкция async/await
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
 
6 создание распределенных приложений по технологии remoting
6 создание распределенных приложений по технологии remoting6 создание распределенных приложений по технологии remoting
6 создание распределенных приложений по технологии remoting
 
Компонентная среда разработки инструментария нагрузочного тестирования
Компонентная среда разработки инструментария нагрузочного тестированияКомпонентная среда разработки инструментария нагрузочного тестирования
Компонентная среда разработки инструментария нагрузочного тестирования
 
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
Примеры быстрой разработки API на масштабируемом сервере приложений Impress д...
 
Reactive Extensions
Reactive ExtensionsReactive Extensions
Reactive Extensions
 
анализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестированияанализ кода: от проверки стиля до автоматического тестирования
анализ кода: от проверки стиля до автоматического тестирования
 
Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2
 
Инструментируй это
Инструментируй этоИнструментируй это
Инструментируй это
 
Многопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиМногопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметки
 
ASP.NET MVC: new era?
ASP.NET MVC: new era?ASP.NET MVC: new era?
ASP.NET MVC: new era?
 
Rx
RxRx
Rx
 
CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...
CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...
CodeFest 2013. Козлов А. — Автоматизация тестирования веб-приложений с исполь...
 
вспомогательные алгоритмы
вспомогательные алгоритмывспомогательные алгоритмы
вспомогательные алгоритмы
 

Mais de Sergey Teplyakov

Void safety on Kiev ALT.NET
Void safety on Kiev ALT.NETVoid safety on Kiev ALT.NET
Void safety on Kiev ALT.NETSergey Teplyakov
 
Тонкости асинхронного программирования
Тонкости асинхронного программированияТонкости асинхронного программирования
Тонкости асинхронного программированияSergey Teplyakov
 
MS SWIT 2013 Design for Testability
MS SWIT 2013 Design for TestabilityMS SWIT 2013 Design for Testability
MS SWIT 2013 Design for TestabilitySergey Teplyakov
 

Mais de Sergey Teplyakov (7)

Void safety on Kiev ALT.NET
Void safety on Kiev ALT.NETVoid safety on Kiev ALT.NET
Void safety on Kiev ALT.NET
 
Тонкости асинхронного программирования
Тонкости асинхронного программированияТонкости асинхронного программирования
Тонкости асинхронного программирования
 
C sharp deep dive
C sharp deep diveC sharp deep dive
C sharp deep dive
 
MS SWIT 2013 Design for Testability
MS SWIT 2013 Design for TestabilityMS SWIT 2013 Design for Testability
MS SWIT 2013 Design for Testability
 
Design by Contract basics
Design by Contract basicsDesign by Contract basics
Design by Contract basics
 
Visual studio toolbox
Visual studio toolboxVisual studio toolbox
Visual studio toolbox
 
Reactive extensions
Reactive extensionsReactive extensions
Reactive extensions
 

Luxoft async.net

  • 2. О Вашем инструкторе  Сергей Тепляков  Visual C# MVP, RSDN Team member  Sergey.Teplyakov@gmail.com  SergeyTeplyakov.blogspot.com 1-2
  • 3. Цели курса… Слушатели изучат:  Достоинства и недостатки синхронного программирования  Существующие паттерны асинхронного программирования на платформе .Net  Использование библиотеки PowerThreading  Использование библиотеки TPL  Новые возможности C# 5 1-3
  • 4. Необходимая подготовка Слушатели должны:  Быть знакомы с основами языка C# и платформы .Net  Обладать базовыми знаниями многопоточности 1-4
  • 5. Roadmap  Модель синхронного программирования  Паттерны асинхронного программирования на платформе .Net  Недостатки существующих моделей  Библиотека PowerThreading  Библиотека TPL  C# 5.0: async и await 1-5
  • 6. Недостатки синхронного программирования  Плохая масштабируемость  Блокирование пользовательского интерфейса  Низкая эффективность операций ввода/вывода  Невозможность использования в некоторых контекстах (например, с JavaScript и Silverlight)
  • 7. Плохая масштабируемость. последовательное выполнение sd Sync Client HttpWebRequest webRequest1.GetWebResponce() ProcessWebResponce1() webRequest2.GetWebResponce() ProcessWebResponce2()
  • 8. Плохая масштабируемость  Неэффективное использование мощностей современных многоядерных процессоров для CPU-Bound операций  Неэффективное выполнение IO-Bound операций даже для одноядерных процессоров
  • 10. Блокировка пользовательского интерфейса // Обработчик кнопки получения данных от веб-страниц private void receiveDataButton_Click(object sender, EventArgs e) { Stopwatch sw = Stopwatch.StartNew(); // 1 _summaryContentLength = 0; // 2 foreach (var url in urls) { // GetResponse возвращает результат синхронно using (WebResponse webResponse = GetResponse(url)) // 3 { ProcessResponse(webResponse); // 4 executionTimeTextBox.Text = sw.ElapsedMilliseconds.ToString(); } } }
  • 11. А ведь это и не всегда возможно!  Некоторые среды, такие как Silverlight и JavaScript не поддерживают синхронные операции
  • 12. Рассматриваемые темы  Модель синхронного программирования  Паттерны асинхронного программирования на платформе .Net  Недостатки существующих моделей  Библиотека PowerThreading  Библиотека TPL  C# 5.0: async и await
  • 13. Асинхронная модель программирования  Два паттерна асинхронного программирования  Classical Async Pattern  Event-Based Async Pattern
  • 14. Classical Async Pattern  Структура паттерна: // Синхронный метод public <return> Operation(<parameters>, <out params> ) // Методы классического асинхронного паттерна public IAsyncResult BeginOperation(<parameters>, AsyncCallback callback, object state) public <return> EndOperation(IAsyncResult asyncResult, <out paramss>)  Пример: public WebResponse GetWebResponse(string url, out TimeSpan duration); public IAsyncResult BeginGetWebResponse(string ulr, object state); public WebResponse EndGetWebResponse(IAsyncResult ar, out TimeSpan duration);
  • 15. Classical Async Pattern  Метод BeginXXX инициирует асинхронную операцию  Метод BeginXXX возвращает IAsyncResult, который является маркером асинхронной операции  AsyncCallback представляет собой функцию, которая будет вызвана при завершении операции  State представляет собой любой пользовательский объект
  • 16. Classical Async Pattern  Все by-value и by-ref параметры синхронного метода становятся by-value параметрами BeginXXX метода  Тип возвращаемого значения синхронного метода совпадает с типом возвращаемого значения EndXXX метода  ref и out параметры синхронного метода добавляются в EndXXX метод  Исключения, генерируемые синхронным методом, генерируются методом EndXXX
  • 17. Примеры Classical Async Pattern  Класс System.IO.Stream public int Read(byte[] buffer, int offset, int count) public IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) public int EndRead(IAsyncResult asyncResult)  Класс System.Net.WebRequest public WebResponse GetWebResponse(); public IAsyncResult BeginGetWebResponse(AsyncCallback callback, object state); public WebResponse EndGetResponse(IAsyncResult asyncResult);
  • 18. Асинхронное выполнение sd ClassicAsync Form Client HttpWebRequest IO completion webRequest1.BeginGetResponse() webRequest2.BeginGetResponse() webRequest2.ProcessResponse() ProcessResponse() UpdateUIElements() webRequest1.ProcessResponse() ProcessResponse() UpdateUIElements()
  • 19. Classical Async Pattern  В обработчике UI события:  Проинициализировать дополнительные поля (теперь без них не обойтись)  Сделать неактивной кнопку  В цикле начать все операции асинхронно (вызывать метод BeginGetResponse)
  • 20. Classical Async Pattern  В обработчике завершения асинхронной операции:  Получить WebResponse (вызывать метод EndGetReponse)  Обработать ответ, не забывая, что обработка происходит не в потоке UI  Понять, что все асинхронные операции завершены (??) (посчитать количество завершенных операций)  Сделать активной кнопку, если все операции таки завершены  Если перед началом выполнения асинхронных операций были выделены ресурсы, то освободить их вручную
  • 21. Разница синхронного и асинхронного вариантов для трех веб-узлов  Среднее выполнение синхронного варианта: 520мс  Среднее выполнение асинхронного варианта: 280 мс  Количество строк кода в синхронном решении: 20  Количество строк кода в асинхронном решении: 78
  • 23. Event-Based Async Pattern class Class Model AsyncCompletedEv entArgs Находится в пространстве + Canceled: bool имен: System.ComponentModel Событие MethodCompleted + Error: Exception вызывается как при успешном, + UserState: object так и при неудачном завершении метода. Метод CancelMethod и событие ProgressChanged являются опциональными. MethodCompletedEv entArgs SomeType Uses + Arg1: int + event MethodCompleted + Arg2: string + event ProgressChanged + Result: MethodResult + CancelMethod() : void Uses + MethodAsync(string, int) : void MethodResult
  • 24. Event-Based Async Pattern  MethodAsync инициирует асинхронную операцию  Есть только одно событие MethodCompleted, EventArgs которого содержат Result, Error, IsCanceled  Возможна, но не обязательна, поддержка отмены и прогресса выполнения
  • 25. Event-Based Async Pattern  By-value и ref параметры синхронного метода являются входными параметрами метода MethodAsync  Ref и out-параметры становятся readonly полями MethodCompletedEventArgs  Событие MethodCompleted вызывается в «правильном» потоке (в потоке UI для WinForms или WPF)
  • 26. Event-Based Async Pattern // Функция обработки принятых данных private void receiveDataButton_Click(object sender, EventArgs e) { // Подготовка операции (отключение кнопки «Принять», // инициализация счетчиков и т.д. foreach (var url in urls) { var webClient = new WebClient(); webClient.DownloadDataAsync(new Uri(url)); webClient.DownloadDataCompleted += (s, ev) => { // Для обработки ошибки в этом случае нужно // обратиться к ствойству ev.Error. // Обработка результатов }; } }
  • 27. Да как же между ними выбрать?  Классический паттерн более низкоуровневый и более гибкий  Event-Based паттерн более простой в применении, в частности с UI дизайнерами  Классический паттерн – для кода общего назначения, Event-Based – для компонентов  Не применяйте оба паттерна для одного класса
  • 28. Рассматриваемые темы  Модель синхронного программирования  Паттерны асинхронного программирования на платформе .Net  Недостатки существующих моделей  Библиотека PowerThreading  Библиотека TPL  C# 5.0: async и await
  • 29. Недостатки моделей асинхронного программирования  Непонятный поток исполнения (Control Flow)  Сложность чтения кода и его сопровождения  Сложность обработки ошибок  Невозможность использования привычных языковых конструкций (using, try/finally etc)
  • 30. Рассматриваемые темы  Модель синхронного программирования  Паттерны асинхронного программирования на платформе .Net  Недостатки существующих моделей  Библиотека PowerThreading  Библиотека TPL  C# 5.0: async и await
  • 31. PowerThreading Library  Разработана Джеффри Рихтер и компанией Wintellect  Содержит класс AsyncEnumerator для упрощения работы с асинхронными операциями  Содержит вспомогательные классы для работы с многопоточностью (ResourceLock, ReaderWriterGate etc)  Другие вспомогательные классы (Disposer, Exception<T>, Singleton etc)
  • 32. Класс AsyncEnumerator. Основные концепции  Поддерживает гибкое управление асинхронными операциями (отмену, таймауты и т.п.)  Использует преимущество блока итераторов (Iterator block) для упрощения потока исполнения  Использует SynchronizationContext для маршалинга потока выполнения в поток UI
  • 33. Класс AsyncEnumerator. Простой пример static IEnumerator<int> WorkerMethod() { // Инициируем n асинхронных операций, // вызываем BeginRead, BeginGetWebResponse, BeginExecuteCommand etc // "возвращаем" n, что говорит AsyncEnumerator-у // о количестве запущенных асинхронных операций yield return n; // класс AsyncEnumerator вызовет в следующий раз // метод MoveNext нашего енумератора (и мы здесь получим управление) // только после завершения указанного количества асинхронных операций. // Причем, если экземпляр класса AsyncEnumerator-а создавался // с контекстом синхронизации (например, он создавался в потоке UI) // то метод MoveNext будет вызван в потоке UI! // Начинаем еще несколько асинхронных операций (например, k) yield return k; } // Создаем экземпляр енумератора AsyncEnumerator ae = new AsyncEnumerator(); // Запускаем асинхронные операции, всю грязную работу // берет на себя AsyncEnumerator ae.BeginExecute(WorkerMethod(), ae.EndExecute);
  • 34. Отступление от темы. Блоки итераторов static IEnumerator<int> GetNumbers() { string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); Console.WriteLine(padding + "Сразу перед yield return 7"); yield return 7; Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42"); yield return 42; Console.WriteLine(padding + "Сразу после yield return 42"); }
  • 35. Визуализация итераторов static IEnumerator<int> GetNumbers() WriteLine("Вызываем GetNumbers()"); { IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); // 1 WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7"); // 2 bool more = iterator.MoveNext(); yield return 7; // 3 WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); // 4 Console.WriteLine(padding + "Сразу перед yield return 42"); // 5 WriteLine("Снова вызываем MoveNext()..."); yield return 42; // 6 more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42"); //7 WriteLine("Result=...", iterator.Current); } WriteLine("Снова вызываем MoveNext()..."); more = iterator.MoveNext(); WriteLine("Result={0} (stopping)", more); Результат: Вызываем GetNumbers()
  • 36. Визуализация итераторов static IEnumerator<int> GetNumbers() WriteLine("Вызываем GetNumbers()"); { IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7"); bool more = iterator.MoveNext(); yield return 7; WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42"); WriteLine("Снова вызываем MoveNext()..."); yield return 42; // 6 more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42"); WriteLine("Result=...", iterator.Current); } WriteLine("Снова вызываем MoveNext()..."); more = iterator.MoveNext(); WriteLine("Result={0} (stopping)", more); Результат: Вызываем GetNumbers() Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7 Result=True; Current=7
  • 37. Визуализация итераторов static IEnumerator<int> GetNumbers() WriteLine("Вызываем GetNumbers()"); { IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7"); bool more = iterator.MoveNext(); yield return 7; WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42"); WriteLine("Снова вызываем MoveNext()..."); yield return 42; more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42"); WriteLine("Result=...“, iterator.Current); } WriteLine("Снова вызываем MoveNext()..."); more = iterator.MoveNext(); WriteLine("Result={0} (stopping)", more); Результат: Вызываем GetNumbers() Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7 Result=True; Current=7 Снова вызываем MoveNext()... Сразу после yield return 7 Сразу перед yield return 42 Result=True; Current=42
  • 38. Визуализация итераторов static IEnumerator<int> GetNumbers() WriteLine("Вызываем GetNumbers()"); { IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7"); bool more = iterator.MoveNext(); yield return 7; WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42"); WriteLine("Снова вызываем MoveNext()..."); yield return 42; more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42"); WriteLine("Result=...", iterator.Current); } WriteLine("Снова вызываем MoveNext()..."); more = iterator.MoveNext(); WriteLine("Result={0} (stopping)", more); Результат: Вызываем GetNumbers() Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7 Result=True; Current=7 Снова вызываем MoveNext()... Сразу после yield return 7 Сразу перед yield return 42 Result=True; Current=42 Result=False (stopping)
  • 39. AsyncEnumerator. Участники  Класс AsyncEnumerator  Рабочий метод, возвращающий IEnumerator<int>  Кто-то, связывающий все это воедино
  • 40. AsyncEnumerator sd AsyncEnumerator AsyncEnumerator WorkerMethod WebRequest IO Completion calling to MoveNext() webRequest1.BeginGetResponse() Первый вызов MoveNext енумератора инициирует ас инхронные операции. webRequest2.BeginGetResponse() WebRequest2Complete() WebRequest1Complete() calling to MoveNext() Т еперь рабочий метод В качес тве метода обработки (WorkerMethod) может обработать завершения ас инхронной завершенные операции и начать операции передаетс я метод новые ас инхронные операции. клас с а AsyncEnumerator-а.
  • 41. Пример использования класса AsyncEnumerator private IEnumerator<int> GetWebData(AsyncEnumerator enumerator) { // Начинаем несколько асинхронных операций WebRequest webRequest1 = WebRequest.Create(url1); webRequest1.BeginGetResponse(enumerator.End(), null); WebRequest webRequest2 = WebRequest.Create(url2); webRequest2.BeginGetResponse(enumerator.End(), null); yield return 2; // 2 - это количество асинхронных операций // Сюда мы попадем уже тогда, когда все асинхронные операции завершены WebResponse webResponse1 = webRequest1.EndGetResponse(enumerator.DequeueAsyncResult()); WebResponse webResponse2 = webRequest2.EndGetResponse(enumerator.DequeueAsyncResult()); // Обрабатываем полученные результаты аналогичным образом }
  • 42. Пример использования класса AsyncEnumerator private void receiveDataButton_Click(object sender, EventArgs e) { asyncEnumerator = new AsyncEnumerator(); // AsyncEnumerator автоматически запоминает контекст синхронизации // Запускаем процесс получения данных асинхронно asyncEnumerator.BeginExecute(GetWebData(asyncEnumerator), asyncEnumerator.EndExecute); }
  • 43. Рассматриваемые темы  Модель синхронного программирования  Паттерны асинхронного программирования на платформе .Net  Недостатки существующих моделей  Библиотека PowerThreading  Библиотека TPL  C# 5.0: async и await
  • 44. Библиотека TPL  Параллелизм задач  Класс Parallel (Parallel.ForEach etc)  Parallel LINQ (a.k.a. PLINQ)
  • 45. Ключевые классы  Task – инкапсулирует единицу работы  Task<TResult> - единица работы с определенным типом результата  TaskFactory, TaskFactory<TResult> – фабрики создания задач  TaskScheduler – управляет «расписанием» запуска задач  TaskCompletionSource – управляет «временем жизни» задачи
  • 46. Класс Task<T>  Представляет собой «незавершенную операцию» или «единицу работы»  Это может быть операция ввода/вывода, операция в фоновом потоке, в выделенном потоке и т.д.  Поддерживает «продолжения» с помощью ContinueWith var task2 = task1.ContinueWith(t => … t.Result …);  Содержит ряд вспомогательных методов: WhenAll, WhenAny etc
  • 47. Примеры использования 1. Простая задача Task.Factory.StartNew(() => Console.WriteLine("Hello from a task!")); 2. Запуск задачи в выделенном потоке Task task = Task.Factory.StartNew( () => { Console.WriteLine("Выполняем длительную операцию"); Thread.Sleep(TimeSpan.FromHours(1)); Console.WriteLine("Длительная операция завершена"); }, TaskCreationOptions.LongRunning);
  • 48. Примеры использования 3. Получение данных от веб-узла Task<long> task = new Task<long>(() => { var webRequest = WebRequest.Create(url); using (var webResponse = webRequest.GetResponse()) { return webResponse.ContentLength; } } ); task.Start(); task.Wait(); long result = task.Result; 4. Использование классического асинхронного API var webRequest = WebRequest.Create(url); Task<WebResponse> task = Task<WebResponse>.Factory.FromAsync( webRequest.BeginGetResponse, webRequest.EndGetResponse, null); task.Wait(); var response = task.Result;
  • 49. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены");
  • 50. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: (ничего не происходит, поскольку задача еще не запущена)
  • 51. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: (все еще ничего не происходит, поскольку первая задача не запущена) (первой задаче установлена вторая задача в виде продолжения)
  • 52. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: (все еще ничего не происходит, поскольку первая задача не запущена) (Связке первых двух задач установлена третья задача в виде продолжения)
  • 53. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: Запускаем первую задачу
  • 54. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: Запускаем первую задачу Ожидаем завершения цепочки задач
  • 55. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется первая задача) Запускаем первую задачу Ожидаем завершения цепочки задач Task1...
  • 56. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется вторая задача, поскольку первая уже завершилась) Запускаем первую задачу Ожидаем завершения цепочки задач Task1... Task2...
  • 57. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется третья задача, поскольку первая и вторая уже завершились) Запускаем первую задачу Ожидаем завершения цепочки задач Task1... Task2... Task3...
  • 58. Продолжения Task task1 = new Task(() => Console.WriteLine("Task1...")); Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2...")); Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3...")); // Запускаем цепочку задач Console.WriteLine("Запускаем первую задачу"); task1.Start(); Console.WriteLine("Ожидаем завершения цепочки задач"); task3.Wait(); Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется третья задача, поскольку первая и вторая уже завершились) Запускаем первую задачу Ожидаем завершения цепочки задач Task1... Task2... Task3... Все задачи завершены
  • 59. Рассматриваемые темы  Модель синхронного программирования  Паттерны асинхронного программирования на платформе .Net  Недостатки существующих моделей  Библиотека PowerThreading  Библиотека TPL  C# 5.0: async и await
  • 60. Модель асинхронного программирования в C# 5  Аналогична синхронной модели  Построена по тому же принципу, что и класс AsyncEnumerator  Использует Task<T> для асинхронных операций  Никто не знает, когда выйдет C# 5  Сейчас доступно Async CTP (Community Technology Preview)
  • 61. Модель асинхронного программирования в C# 5  Два новых ключевых слова:  async – указывает, что метод или лямбда- выражение является асинхронным  await – является аналогом yield return и возвращает сразу же управление вызывающему коду до тех пор, пока асинхронная операция не будет завершена
  • 62. Модель асинхронного программирования в C# 5 static async Task<long> GetWebResponseContentLength(string url) { var webRequest = WebRequest.Create(url); Console.WriteLine("Перед вызовом await-a. Thread Id: {0}", Thread.CurrentThread.ManagedThreadId); // Начинаем асинхронную операцию Task<WebResponse> responseTask = webRequest.GetResponseAsync(); // Ожидаем получения ответа WebResponse webResponse = await responseTask; Console.WriteLine("После завершения await-а. Thread Id: {0}", Thread.CurrentThread.ManagedThreadId); // В этой строке мы уже получили ответ от веб-узла // можем обрабатывать результаты. Тип возвращаемого значения // должен соответствовать обобщенному параметру класса Task return webResponse.ContentLength; }
  • 63. Работа простого метода WriteLine("Начало исполнения. Thread Id: {0}"); static async Task<long> GetWebResponseContentLength(string url) { Task<long> task = var webRequest = WebRequest.Create(url); GetWebResponseContentLength(url); WriteLine("Перед вызовом await-a. Thread Id: {0}"); // ожидаем завершения асинхронной операции // Начинаем асинхронную операцию task.Wait(); Task<WebResponse> respTsk = webRequest.GetResponseAsync(); WriteLine("ContentLength: {0}, Thread Id: {1}"); // Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); Результаты: Начало исполнения. Thread Id: 10 return webResponse.ContentLength; } Перед вызовом await-a. Thread Id: 10 (Асинхронная операция запущена)
  • 64. Работа простого метода WriteLine("Начало исполнения. Thread Id: {0}"); static async Task<long> GetWebResponseContentLength(string url) { Task<long> task = var webRequest = WebRequest.Create(url); GetWebResponseContentLength(url); WriteLine("Перед вызовом await-a. Thread Id: {0}"); // ожидаем завершения асинхронной операции // Начинаем асинхронную операцию task.Wait(); Task<WebResponse> respTsk = webRequest.GetResponseAsync(); WriteLine("ContentLength: {0}, Thread Id: {1}"); // Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); Результаты: return webResponse.ContentLength; Начало исполнения. Thread Id: 10 } Перед вызовом await-a. Thread Id: 10 После завершения await-a. Thread Id: 14 (Эта строка выполнится только после завершения операции)
  • 65. Работа простого метода WriteLine("Начало исполнения. Thread Id: {0}"); static async Task<long> GetWebResponseContentLength(string url) { Task<long> task = var webRequest = WebRequest.Create(url); GetWebResponseContentLength(url); WriteLine("Перед вызовом await-a. Thread Id: {0}"); // ожидаем завершения асинхронной операции // Начинаем асинхронную операцию task.Wait(); Task<WebResponse> respTsk = webRequest.GetResponseAsync(); WriteLine("ContentLength:{0},Thread Id: {1}"); // Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); Результаты: return webResponse.ContentLength; } Начало исполнения. Thread Id: 10 Перед вызовом await-a. Thread Id: 10 После завершения await-a. Thread Id: 14 ContentLength: 1672, Thread Id: 10
  • 66. Сравнение с AsyncEnumerator  IEnumerator<T> -> async Task<T>  yield return n -> await task
  • 67. Модель асинхронного программирования в C# 5  Асинхронный метод может возвращать  void – для асинхронных операций типа “fire and forget”  Task – вызывающий код может дождаться завершения асинхронной операции, которая не возвращает значения  Task<T> - для асинхронной операции, возвращающей T (string для Task<string> etc)
  • 68. Модель асинхронного программирования C# 5 private async void receiveDataButton_Click(object sender, EventArgs e) { Stopwatch sw = Stopwatch.StartNew(); receiveDataButton.Enabled = false; IEnumerable<Task<WebResponse>> tasks = from url in urls let webRequest = WebRequest.Create(url) select webRequest.GetResponseAsync(); // Начинаем выполнять все задачи WebResponse[] webResponses = await TaskEx.WhenAll(tasks); // Теперь мы можем обработать результаты long summaryContentLength = webResponses.Sum(s => s.ContentLength); executionTimeTextBox.Text = sw.ElapsedMilliseconds.ToString(); summaryContentLengthTextBox.Text = summaryContentLength.ToString(); receiveDataButton.Enabled = true; foreach(var wr in webResponses) wr.Close(); }
  • 69. Преимущества новой асинхронной модели  Простота использования  Привычный поток исполнения  Простота обработки ошибок и возможность использования конструкций using, try/finally etc try { WebResponse[] data = await TaskEx.WhenAll(tasks); // Обработка данных } catch (WebException we) { //Обработка ошибки получения данных }
  • 70. Преимущества новой асинхронной модели  Построена на основе проверенных идиом (Iterator blocks, AsyncEnumerator, Reactive Extensions)  Построена на основе TPL (преимущества от ее использования можно закладывать уже сейчас)
  • 71. Что мы изучили?  Модель синхронного программирования  Паттерны асинхронного программирования на платформе .Net  Недостатки существующих моделей  Библиотека PowerThreading  Библиотека TPL  C# 5.0: async и await
  • 72. Дополнительные ссылки  Visual Studio Asynchronous Programming (http://msdn.microsoft.com/en- us/vstudio/async.aspx)  Асинхронные операции и AsyncEnumerator (http://sergeyteplyakov.blogspot.com/2010/10/asyncenumerator.html)  «Реактивные расширения и асинхронные операции (http://sergeyteplyakov.blogspot.com/2010/11/blog-post.html)  Знакомство с асинхронными операциями в C# 5 (http://sergeyteplyakov.blogspot.com/2010/12/c-5.html)  Джефри Рихтер. Упрощение модели асинхронного программирования с помощью AsyncEnumerator (http://msdn.microsoft.com/ru- ru/magazine/cc546608.aspx)  Джеффри Рихтер. Дополнительные возможности AsyncEnumerator (http://msdn.microsoft.com/ru-ru/magazine/cc721613.aspx)
  • 73. Дополнительные ссылки  Итераторы в языке программирования C#  Часть 1: http://sergeyteplyakov.blogspot.com/2010/06/c-1.html  Часть 2: http://sergeyteplyakov.blogspot.com/2010/06/c-2.html  Часть 3: http://sergeyteplyakov.blogspot.com/2010/06/c-3.html  Eric Lippert. Continuation Passing Style: http://blogs.msdn.com/b/ericlippert/archive/tags/continuation+passing+styl e/  Reactive Extensions Official release (http://channel9.msdn.com/Blogs/Charles/Announcing-the-Official-Release- of-Rx)