Язык программирования C#9 и платформа .NET5
int[] modThreeIsZero = (from num in source.AsParallel()where num % 3 == 0orderby num descending select num).ToArray();Обратите внимание, что общий формат запроса LINQ идентичен тому, что вы видели в предыдущих главах. Тем не менее, за счет включения вызова
библиотека TPL попытается распределить рабочую нагрузку по доступным процессорам.AsParallel()Отмена запроса PLINQ
С помощью объекта
запрос PLINQ можно также информировать о прекращении обработки при определенных условиях (обычно из-за вмешательства пользователя). Объявите на уровне классаCancellationTokenSourceобъектProgramпо имениCancellationTokenSourceи модифицируйте операторы верхнего уровня для принятия ввода от пользователя. Ниже показаны соответствующие изменения в коде:_cancelTokenCancellationTokenSource _cancelToken =new CancellationTokenSource();do{Console.WriteLine("Start any key to start processing");// Нажмите любую клавишу, чтобы начать обработкуConsole.ReadKey();Console.WriteLine("Processing");Task.Factory.StartNew(ProcessIntData);Console.Write("Enter Q to quit: ");// Введите Q для выхода:string answer = Console.ReadLine();// Желает ли пользователь выйти?if (answer.Equals("Q",StringComparison.OrdinalIgnoreCase)){_cancelToken.Cancel();break;}}while (true);Console.ReadLine();Теперь запрос PLINQ необходимо информировать о том, что он должен ожидать входящего запроса на отмену выполнения, добавив в цепочку вызов расширяющего метода
с передачей ему маркера отмены. Кроме того, этот запрос PLINQ понадобится поместить в подходящий блокWithCancellation()и обработать возможные исключения. Финальная версия методаtry/catchвыглядит следующим образом:ProcessInData()void ProcessIntData(){// Получить очень большой массив целых чисел.int[] source = Enumerable.Range(1, 10_000_000).ToArray();// Найти числа, для которых истинно условие num % 3 == 0,// и возвратить их в убывающем порядке.int[] modThreeIsZero = null;try{modThreeIsZero =(from num in source.AsParallel().WithCancellation(_cancelToken.Token)where num % 3 == 0orderby num descendingselect num).ToArray();Console.WriteLine();// Вывести количество найденных чисел.Console.WriteLine($"Found {modThreeIsZero.Count()} numbersthat match query!");}catch (OperationCanceledException ex){Console.WriteLine(ex.Message);}}Во время выполнения метода
понадобится нажать <Q> и быстро произвести ввод, чтобы увидеть сообщение от маркера отмены.ProcessIntData()Асинхронные вызовы с помощью async/await
В этой довольно длинной главе было представлено много материала в сжатом виде. Конечно, построение, отладка и понимание сложных многопоточных приложений требует прикладывания усилий в любой инфраструктуре. Хотя TPL, PLINQ и тип делегата могут до некоторой степени упростить решение (особенно по сравнению с другими платформами и языками), разработчики по-прежнему должны хорошо знать детали разнообразных расширенных приемов.
С выходом версии .NET 4.5 в языке программирования C# появились два новых ключевых слова, которые дополнительно упрощают процесс написания асинхронного кода. По контрасту со всеми примерами, показанными ранее в главе, когда применяются ключевые слова
иasync, компилятор будет самостоятельно генерировать большой объем кода, связанного с потоками, с использованием многочисленных членов из пространств именawaitиSystem.Threading.System.Threading.TasksЗнакомство с ключевыми словами async и await языка C# (обновление в версиях 7.1, 9.0)
Ключевое слово
языка C# применяется для указания на то, что метод, лямбда-выражение или анонимный метод должен вызываться в асинхронной манере автоматически. Да, это правда. Благодаря простой пометке метода модификаторомasyncсреда .NET Core Runtime будет создавать новый поток выполнения для обработки текущей задачи. Более того, при вызове методаasyncключевое словоasyncбудет автоматически приостанавливать текущий поток до тех пор, пока задача не завершится, давая возможность вызывающему потоку продолжить свою работу.awaitВ целях иллюстрации создайте новый проект консольного приложения по имени
и импортируйте в файлFunWithCSharpAsyncпространства именProgram.cs,System.ThreadingиSystem.Threading.Task. Добавьте методSystem.Collections.Generic, который заставляет вызывающий поток ожидать пять секунд. Ниже показан код:DoWork()