Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка ПИ Программирование на С# _Хотов.docx
Скачиваний:
4
Добавлен:
01.07.2025
Размер:
2.22 Mб
Скачать
      1. Последовательный и параллельный вызов асинхронных методов

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

static async Task DisplayResultAsync()

{

int num = 5;

int result = await FactorialAsync(num);

Console.WriteLine("Факториал числа {0} равен {1}", num, result);

num = 6;

result = FactorialAsync(num).GetAwaiter().GetResult();

Console.WriteLine("Факториал числа {0} равен {1}", num, result);

result = await Task.Run(() =>

{

int res = 1;

for (int i = 1; i <= 9; i++)

{

res += i*i;

}

return res;

});

Console.WriteLine("Сумма квадратов чисел равна {0}", result);

}

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

Однако не всегда существует подобная зависимость между задачами. В этом случае мы можем запустить все задачи одновременно через метод Task.WhenAll:

static async Task DisplayResultAsync()

{

int num1 = 5;

int num2 = 6;

Task<int> t1 = FactorialAsync(num1);

Task<int> t2 = FactorialAsync(num2);

Task<int> t3 = Task.Run(() =>

{

int res = 1;

for (int i = 1; i <= 9; i++)

{

res += i * i;

}

return res;

});

await Task.WhenAll(new[] { t1, t2, t3 });

Console.WriteLine("Факториал числа {0} равен {1}", num1, t1.Result);

Console.WriteLine("Факториал числа {0} равен {1}", num2, t2.Result);

Console.WriteLine("Сумма квадратов чисел равна {0}", t3.Result);

}

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

      1. Обработка ошибок в асинхронных методах

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

Для обработки ошибок вызов асинхронного метода с await помещается в блок try:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

namespace AsyncExceptionApp

{

class Program

{

static void Main(string[] args)

{

DisplayResultAsync(0).Wait();

Console.ReadLine();

}

static async Task DisplayResultAsync(int num)

{

try

{

int result = await Factorial(num);

Thread.Sleep(3000);

Console.WriteLine("Факториал числа {0} равен {1}", num, result);

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

}

}

static async Task<int> Factorial(int x)

{

int result = 1;

if (x < 1)

throw new Exception("Число не должно быть меньше 1");

return await Task.Run(() =>

{

for (int i = 1; i <= x; i++)

{

result *= i;

}

return result;

});

}

}

}

При возникновении ошибки у объекта Task, представляющего асинхронную задачу, в которой произошла ошибка, свойствоIsFaulted имеет значение true. Кроме того, свойство Exception объекта Task содержит всю информацию об ошибке. Чтобы проинспектировать свойство, изменим метод DisplayResultAsync следующим образом:

static async Task DisplayResultAsync(int num)

{

Task<int> fact = Factorial(num);

try

{

int result = await fact;

Thread.Sleep(3000);

Console.WriteLine("Факториал числа {0} равен {1}", num, result);

}

catch (Exception ex)

{

Console.WriteLine(fact.Exception.InnerException.Message);

Console.WriteLine("IsFaulted: {0}", fact.IsFaulted);

}

}

И если мы передадим в метод число 0, то fact.IsFaulted будет равно true.