Запросы без результатов
89LINQ --- PLINQ --- Запросы без результатов
PLINQ включает полезное средство в расширяющем методе ForAll. Использованный с объектом ParallelQuery (который, как известно, возвращается методом AsParallel), ForAll выполняет System.Action на каждом элементе в последовательности. В одном из рассмотренных ранее примеров ищутся все названия машин, содержащие букву "s". Для фильтрации соответствующих имен использовалась конструкция where, а выбранные имена добавлялись к результирующей коллекции IEnumerable<string>. Затем результаты перечисляются в цикле foreach с выводом их на консоль посредством Console.WriteLine.
С помощью метода ForAll можно сделать то же самое, но намного элегантнее. Рассмотрим код ниже:
string[] cars = { "Nissan", "Aston Martin", "Chevrolet", "Alfa Romeo", "Chrysler", "Dodge", "BMW",
"Ferrari", "Audi", "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};
// Запрос Parallel LINQ
cars.AsParallel()
.Where(p => p.Contains("s"))
.ForAll(p => Console.WriteLine("Название: " + p));
Здесь по-прежнему используется метод Where для фильтрации последовательности, но вместо сбора результатов имена выводятся на консоль непосредственно, с применением лямбда-выражения, переданного методу ForAll. Чтобы понять работу этого средства, может потребоваться некоторое время. В конце концов, все прочие примеры, приведенные ранее, функционировали иначе. Однако метод ForAll стоит знать.
Ниже показаны результаты запуска этого кода:
Внутри объекта Action, передаваемого методу ForAll, можно делать довольно много всего за исключением возврата результата. Можно даже фильтровать данные без помощи конструкции Where:
string[] cars = { "Nissan", "Aston Martin", "Chevrolet", "Alfa Romeo", "Chrysler", "Dodge", "BMW",
"Ferrari", "Audi", "Bentley", "Ford", "Lexus", "Mercedes", "Toyota", "Volvo", "Subaru", "Жигули :)"};
int count = 0;
cars.AsParallel()
.ForAll(p =>
{
if (p.Contains('s'))
System.Threading.Interlocked.Increment(ref count);
});
Console.WriteLine("Совпадений: " + count);
В приведенном коде метод ForAll использовался для выполнения действия над каждым элементом в последовательности данных. Для каждого элемента проверяется наличие в имени буквы "s" и увеличивается значение счетчика, если она там есть. Результат запуска кода выглядит следующим образом:
Не забывайте, что метод ForAll является частью PLINQ, а это значит, что указываемое в объекте Action действие выполняется в разделах последовательности данных параллельно. Это дает выигрыш в производительности за счет параллельного выполнения, но может привести к проблемам с разделяемыми данными, такими как значение int, используемое в качестве счетчика совпадений. Для обеспечения точности подсчета применяется класс Interlocked из пространства имен System.Threading. Этот прием называется синхронизацией, и представляет собой расширенную технику параллельного программирования.