Асинхронное программирование необходимо использовать при наличии замедляющих (блокирующих) действий, например при:
• чтении большого файла
• доступ к web странице, сервису
• загрузке данных из базы данных
Эти действия могут происходить медленно (с задержкой) и программа зависает, мышка и клавиатура ни на что не реагирует и приложение вынуждено ожидать(подвисает).
В
асинхронном программировании асинхронные методы работают в фоновом режиме.
Асинхронные методы не блокируют главный поток.
Это позволяет выполнять основные задачи, пока идет работа в фоновом режиме.
Асинхронность особенно полезна в приложениях, которые обращаются к потоку пользовательского интерфейса, поскольку все связанные с пользовательским интерфейсом действия обычно используют один поток. В синхронном приложении блокировка главного потока делает зависание приложения, приложение перестает отвечать.
При использовании
асинхронных методов приложение продолжает реагировать на действия в пользовательском интерфейсе. Например, можно изменить размер окна или свернуть его, либо закрыть приложение.
async, await и Task
Основой асинхронного программирования. являются ключевые слова
async,
await и вместе с функциональностью
Task они составляют основу асинхронного программирования в .NET (
Task-based Asynchronous Pattern).
В C# есть
многопоточное программирование.
В многопоточном программировании нужно самому создовать дополнительные потоки, следить за синхронизацией объектов между потоками. Создание и уничтожение потока снижает производительность.
В асинхронном программировании используя
async,
await и
Task программа легче пишется и эффективнее работает чем потоки.
Чтобы разобраться с
async,
await и
Task напишем пример.
C#
Создаем новое C# консольное приложение... и напишем код
using System;
using System.Collections;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class MyMath
{
public async void LaunchCalculate()
{
// calculate
Task<double> taskValue = AlgorithmSumAsync(123456789); // создается дополнительный поток и ставится в очередь для запуска
// show message
Console.WriteLine("Go next");
// дожидаемся результата (главный поток при виде await выходит из метода LaunchCalculate)
double value = await taskValue;
// дополнительный поток после завершения попадет сюда
// show message
Console.WriteLine("Result = " + value);
}
// sum = sqrt(1) + sqrt(2) + sqrt(3) + ... + sqrt(n)
protected Task<double> AlgorithmSumAsync(int n)
{
return Task.Run(() =>
{
// show message
Console.WriteLine("begin Calculation");
double sum = 1;
for (int i = 1; i <= n; i++)
{
sum += Math.Sqrt(i);
}
// show message
Console.WriteLine("end Calculation");
// return
return sum;
});
}
}
class Program
{
// главный метод программы
static void Main()
{
// show message
Console.WriteLine("Main");
MyMath myMath = new MyMath();
myMath.LaunchCalculate();
// show message
Console.WriteLine("back in Main, please enter symbol");
Console.ReadLine();
}
}
}
-> Main()
-> Console.WriteLine("Main");
-> MyMath myMath = new MyMath();
-> myMath.LaunchCalculate();
-> Task<double> taskValue = AlgorithmSumAsync(123456789);
-> Console.WriteLine("Go next");
-> Когда код попытается выполнить await taskValue; и так как Task не закончен то запомнится эта строчка и сейчас выйдем из метода myMath.LaunchCalculate(); и пойдем по Main методу (паралелно продолжает выполнятся AlgorithmSumAsync Console.WriteLine("begin Calculation");)
-> Console.WriteLine("back in Main, please enter symbol");
-> Console.ReadLine();
-> через какое то время после того как закончит выполняться AlgorithmSumAsync то мы поподем в строчку double value = await taskValue;
-> Console.WriteLine("end Calculation");
-> выполним код Console.WriteLine("Result = " + value);
-> метода LaunchCalculate() завершен (это значит что параллелность закончена)