Introducing
Your new presentation assistant.
Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.
Trending searches
выполняет свою работу перед возвратом управления вызывающему коду.
Примеры:
выполняет (большую часть или всю) свою работу после возврата управления вызывающему коду.
Примеры:
Принцип асинхронного программирования состоит в том, что длительно выполняющиеся функции реализуются асинхронным образом. Он отличается от традиционного подхода синхронной реализации длительно выполняющихся функций с последующим их вызовом в новом потоке или в задаче для введения параллелизма по мере необходимости.
Параллельное выполнение с интенсивным вводом-выводом может быть реализовано без связывания потоков (как далее будет продемонстрировано с применением класса TaskCompletionSource), улучшая показатели масштабируемости и эффективности.
Класс TaskCompletionSource
Данный класс открывает доступ к свойству Task, возвращающему объект задачи, для которой можно организовать ожидание и присоединить признак продолжения – как делается с любой другой задачей.
Обогащенные клиентские приложения в итоге содержат меньше кода в рабочих потоках, что упрощает достижение безопасности в отношении потоков. Это особенно актуально с ростом размера программы, поскольку для борьбы со сложностью мы обычно проводим рефакторинг крупных методов в методы меньших размеров, получая в результате цепочки методов, которые вызывают друг друга (графы вызовов).
В случае методов с интенсивными вычислениями для инициирования параллелизма, связанного с потоками, мы применяем метод Task.Run. Асинхронный метод создается просто за счет возвращения вызывающему компоненту объекта задачи.
Продемонстрируем метод, который
вызывает GetPrimesCount:
Вот как выглядит вывод:
Для реализации асинхронного подхода:
Сделаем метод DisplayPrimesCount
асинхронным.
К счастью, асинхронные функции C# делают всю работу подобного рода благодаря новым ключевым словам async и await:
Ключевое слово await упрощает присоединение признаков продолжения. Рассмотрим базовый сценарий. Приведенные ниже строки:
var результат = await выражение;
оператор(ы);
компилятор развернет в следующий функциональный эквивалент:
var awaiter = выражение.GetAwaiter();
awaiter.OnCompleted(() =>
{
var результат = awaiter.GetResult();
оператор(ы);
);
Модификатор async может применяться только к методам (и лямбда-выражениям), которые возвращают void либо тип Task или Task<TResult>.
Логическое расширение показанного ранее асинхронного метода:
Реальная мощь выражений await заключается в том, что они могут находиться практически в любом месте кода. В следующем примере await располагается внутри цикла:
Продемонстрируем асинхронные функции в более практичном контексте, реализовав простой пользовательский интерфейс, который остается отзывчивым во время вызова метода с интенсивными вычислениями.
После щелчка на кнопке Go приложение перестает быть отзывчивым на время, необходимое для выполнения кода с интенсивными вычислениями.
Решение превращается в асинхронное за два шага:
1. переключение на асинхронную версию метода GetPrimesCount;
2. изменение метода Go для вызова метода GetPrimesCountAsync.
Рассмотрим еще один пример, в котором вместо вычисления простых чисел загружается несколько веб-страниц с суммированием их длин.
Обработчики событий, присоединяемые к элементам пользовательского интерфейса, выполняются через такой цикл сообщений.
while (приложение не завершено)
{
Ожидать появления чего-нибудь в очереди сообщений
Что-то получено: к какому вид у сообщений оно относится?
Сообщение клавиатуры/мыши -> запустить обработчик событий
Пользовательское сообщение Beginlnvoke/Invoke -> выполнить делегат
}