# Конспект лекции "Многопоточность" :()=[,`][]= ### // Задачи и класс Task ## Первый способ создание объекта Task и вызов у него метода Start: ``` Task task = new Task( () => Console.WriteLine("Hello Task!") ); task.Start(); ``` ``` Process finished with exit code 0. ``` ## Второй способ заключается в использовании статического метода Task.Factory.StartNew() ``` Task task = Task.Factory.StartNew( () => Console.WriteLine("Hello Task!") ); ``` ``` Process finished with exit code 0. ``` ## Третий способ определения и запуска задач представляет использование статического метода Task.Run(): ``` Task task = Task.Run( () => Console.WriteLine("Hello Task!") ); ``` ``` Process finished with exit code 0. ``` ## Определим небольшую программу, где используем все эти способы: ``` using System; using System.Threading.Tasks; Task task1 = new Task( () => Console.WriteLine("Task1 is executed")); task1.Start(); Task task2 = Task.Factory.StartNew( () => Console.WriteLine("Task2 is executed")); Task task3 = Task.Run( () => Console.WriteLine("Task3 is executed")); Console.ReadLine(); ``` ``` Task2 is executed Task1 is executed Task3 is executed Process finished with exit code 0. ``` ### // Ожидание задачи ## esempio ``` using System; using System.Threading; Task task = new Task(Display); task.Start(); Console.WriteLine( "Завершение метода Main"); Console.ReadLine(); static void Display() { Console.WriteLine( "Начало работы метода Display"); Console.WriteLine( "Завершение работы метода Display"); } ``` ``` Завершение метода Main Начало работы метода Display Завершение работы метода Display Process finished with exit code 0. ``` ### // Aсинхронное программирование. Асинхронные методы, async и await ## пример асинхронного метода: ``` using System; using System.Threading; using System.Threading.Tasks; // вызов асинхронного метода FactorialAsync(); Console.WriteLine( "Введите число: "); int n = Int32.Parse(Console.ReadLine()); Console.WriteLine( $"Квадрат числа равен {n * n}"); Console.Read(); static void Factorial() { int result = 1; for(int i = 1; i <= 6; i++) { result *= i; } Thread.Sleep(8000); Console.WriteLine( $"Факториал равен {result}"); } // определение асинхронного метода static async void FactorialAsync() { // выполняется синхронно Console.WriteLine( "Начало метода FactorialAsync"); // выполняется асинхронно await Task.Run(()=>Factorial()); Console.WriteLine( "Конец метода FactorialAsync"); } ``` ``` Начало метода FactorialAsync Введите число: 7 Квадрат числа равен 49 Факториал равен 720 Конец метода FactorialAsync Process finished with exit code 0. ``` ## esempio - чтение-запись файла: ``` using System; using System.Threading; using System.Threading.Tasks; using System.IO; ReadWriteAsync(); Console.WriteLine("Некоторая работа"); Console.Read(); static async void ReadWriteAsync() { string s = "Hello world! One step at a time"; // hello.txt - файл, который будет записываться и считываться using (StreamWriter writer = new StreamWriter("hello.txt", false)) { // асинхронная запись в файл await writer.WriteLineAsync(s); } using (StreamReader reader = new StreamReader("hello.txt")) { // асинхронное чтение из файла string result = await reader.ReadToEndAsync(); Console.WriteLine(result); } } ``` ``` Некоторая работа Hello world! One step at a time Process finished with exit code 0. ``` ## мы сами можем определить асинхронную операцию, используя метод Task.Run(): ``` static void Factorial() { int result = 1; for (int i = 1; i <= 6; i++) { result *= i; } Thread.Sleep(8000); Console.WriteLine($"Факториал равен {result}"); } // определение асинхронного метода static async void FactorialAsync() { // вызов асинхронной операции await Task.Run(()=>Factorial()); } ``` ``` Process finished with exit code 0. ``` ## Можно определить асинхронную операцию с помощью лямбда-выражения: ``` static async void FactorialAsync() { await Task.Run(() => { int result = 1; for (int i = 1; i <= 6; i++) { result *= i; } Thread.Sleep(8000); Console.WriteLine($"Факториал равен {result}"); }); } ``` ``` Process finished with exit code 0. ``` ### // Передача параметров в асинхронную операцию ## мы хотим вычислить факториалы разных чисел: ``` using System; using System.Threading; using System.Threading.Tasks; FactorialAsync(5); FactorialAsync(6); Console.WriteLine("Некоторая работа"); Console.Read(); static void Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } Thread.Sleep(5000); Console.WriteLine($"Факториал равен {result}"); } // определение асинхронного метода static async void FactorialAsync(int n) { await Task.Run(()=>Factorial(n)); } ``` ``` Некоторая работа Факториал равен 120 Факториал равен 720 Process finished with exit code 0. ``` ### // Получение результата из асинхронной операции ``` using System; using System.Threading; using System.Threading.Tasks; FactorialAsync(5); FactorialAsync(6); Console.Read(); static int Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } return result; } // определение асинхронного метода static async void FactorialAsync(int n) { int x = await Task.Run(()=>Factorial(n)); Console.WriteLine($"Факториал равен {x}"); } ``` ``` Факториал равен 120 Факториал равен 720 Process finished with exit code 0. ``` ### // Возвращение результата из асинхронного метода ## void ``` static void Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } Console.WriteLine($"Факториал равен {result}"); } // определение асинхронного метода static async void FactorialAsync(int n) { await Task.Run(()=>Factorial(n)); } ``` ``` Process finished with exit code 0. ``` ## Task ``` using System; using System.Threading.Tasks; FactorialAsync(5); FactorialAsync(6); Console.WriteLine("Некоторая работа"); Console.Read(); static void Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } Console.WriteLine($"Факториал равен {result}"); } // определение асинхронного метода static async Task FactorialAsync(int n) { await Task.Run(()=>Factorial(n)); } ``` ``` Факториал равен 120 Факториал равен 720 Некоторая работа Process finished with exit code 0. ``` ## Task ``` using System; using System.Threading.Tasks; int n1 = await FactorialAsync(5); int n2 = await FactorialAsync(6); Console.WriteLine($"n1={n1} n2={n2}"); Console.Read(); static int Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } return result; } // определение асинхронного метода static async Task FactorialAsync(int n) { return await Task.Run(()=>Factorial(n)); } ``` ``` n1=120 n2=720 Process finished with exit code 0. ``` ### // Последовательный и параллельный вызов асинхронных операций ``` using System; using System.Threading.Tasks; FactorialAsync(); Console.Read(); static void Factorial(int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } Console.WriteLine($"Факториал числа {n} равен {result}"); } // определение асинхронного метода static async void FactorialAsync() { await Task.Run(() => Factorial(4)); await Task.Run(() => Factorial(3)); await Task.Run(() => Factorial(5)); } ``` ``` Факториал числа 4 равен 24 Факториал числа 3 равен 6 Факториал числа 5 равен 120 Process finished with exit code 0. ``` ### // Обработка ошибок в асинхронных методах ## Обработка ошибок в асинхронных методах, использующих ключевые слова async и await, имеет свои особенности. ``` using System; using System.Threading; using System.Threading.Tasks; FactorialAsync(-4); FactorialAsync(6); Console.Read(); static void Factorial(int n) { if (n < 1) throw new Exception($"{n} : число не должно быть меньше 1"); int result = 1; for (int i = 1; i <= n; i++) { result *= i; } Console.WriteLine($"Факториал числа {n} равен {result}"); } static async void FactorialAsync(int n) { try { await Task.Run(() => Factorial(n)); } catch (Exception ex) { Console.WriteLine(ex.Message); } } ``` ``` Факториал числа 6 равен 720 -4 : число не должно быть меньше 1 Process finished with exit code 0. ``` ## поломанный код ``` static async void FactorialAsync(int n) { Task task = null; try { task = Task.Run(()=>Factorial(n)); await task; } catch (Exception ex) { Console.WriteLine(task.Exception.InnerException.Message); Console.WriteLine($"IsFaulted: {task.IsFaulted}"); } } ``` ``` error ``` ## эксепшен не эксепшен, вывод с неба упал ``` static async Task DoMultipleAsync() { Task allTasks = null; try { Task t1 = Task.Run(()=>Factorial(-3)); Task t2 = Task.Run(() => Factorial(-5)); Task t3 = Task.Run(() => Factorial(-10)); allTasks = Task.WhenAll(t1, t2, t3); await allTasks; } catch (Exception ex) { Console.WriteLine("Исключение: " + ex.Message); Console.WriteLine("IsFaulted: " + allTasks.IsFaulted); foreach (var inx in allTasks.Exception.InnerExceptions) { Console.WriteLine("Внутреннее исключение: " + inx.Message); } } } ``` ``` Исключение: -3 : число не должно быть меньше 1 IsFaulted: True Внутреннее исключение: -3: число не должно быть меньше 1 Внутреннее исключение: -5: число не должно быть меньше 1 Внутреннее исключение: -10: число не должно быть меньше 1 ``` ## никакой возможности нет, это афера ``` static async void FactorialAsync(int n) { try { await Task.Run(() => Factorial(n)); ; } catch (Exception ex) { await Task.Run(()=>Console.WriteLine(ex.Message)); } finally { await Task.Run(() => Console.WriteLine("await в блоке finally")); } } ``` ``` error ``` ### // Отмена асинхронных операций ``` using System; using System.Threading; using System.Threading.Tasks; CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.Token; FactorialAsync(6, token); Thread.Sleep(3000); cts.Cancel(); Console.Read(); static void Factorial(int n, CancellationToken token) { int result = 1; for (int i = 1; i <= n; i++) { if (token.IsCancellationRequested) { Console.WriteLine( "Операция прервана токеном"); return; } result *= i; Console.WriteLine( $"Факториал числа {i} равен {result}"); Thread.Sleep(1000); } } // определение асинхронного метода static async void FactorialAsync(int n, CancellationToken token) { if(token.IsCancellationRequested) return; await Task.Run(()=>Factorial(n, token)); } ``` ``` Факториал числа 1 равен 1 Факториал числа 2 равен 2 Факториал числа 3 равен 6 Операция прервана токеном Process finished with exit code 0. ```