Public static ParallelQuery AsOrdered(this ParallelQuery source)



public static ParallelQuery<TSource>

AsOrdered<TSource>(this ParallelQuery<TSource> source)

 

где TSource обозначает тип элементов в источнике данных source. Метод AsOrdered() можно вызывать только для объекта типа ParallelQuery, поскольку он является методом расширения класса ParallelQuery.

Для того чтобы посмотреть, к какому результату может привести применение метода AsOrdered(), подставьте его вызов в приведенный ниже запрос из предыдущего примера программы.

 

// Использовать метод AsOrdered() для сохранения порядка

// в результирующей последовательности.

 

var negatives = from val in data.AsParallel().AsOrdered() where val < 0 select val;

 

После выполнения программы порядок следования элементов в результирующей последовательности будет отражать порядок их расположения в исходной последовательности.

 

 

Отмена параллельного запроса

 

Параллельный запрос отменяется таким же образом, как и задача. И в том и в другом случае отмена опирается на структуру CancellationToken, получаемую из класса CancellationTokenSource. Получаемый в итоге признак отмены передается запросу с помощью метода WithCancellation(). Отмена параллельного запроса производится методом Cancel(), который вызывается для источника признаков отмены. Главное отличие отмены параллельного запроса от отмены задачи состоит в следующем: когда параллельный запрос отменяется, он генерирует исключение OperationCanceledException, а не AggregateException. Но в тех случаях, когда запрос способен сгенерировать несколько исключений, исключение OperationCanceledException может быть объединено в совокупное исключение AggregateException. Поэтому отслеживать лучше оба вида исключений.

Ниже приведена форма объявления метода WithCancellation():

 

public static ParallelQuery<TSource> WithCancellation<TSource> (

this ParallelQuery<TSource> source,

CancellationToken cancellationToken)

 

где source обозначает вызывающий запрос, a cancellationToken — признак отмены. Этот метод возвращает запрос, поддерживающий указанный признак отмены.

В приведенном ниже примере программы демонстрируется порядок отмены параллельного запроса, сформированного в программе из предыдущего примера. В данной программе организуется отдельная задача, которая ожидает в течение 100 миллисекунд, а затем отменяет запрос. Отдельная задача требуется потому, что цикл foreach, в котором выполняется запрос, блокирует выполнение метода Main() до завершения цикла.

 

// Отменить паралельный запрос

using System;

using System.Linq;  

using System.Threading;  

using System.Threading.Tasks;  

 

class PLINQCancelDemo {  

static void Main() {  

CancellationTokenSource cancelTokSrc = new CancellationTokenSource();  

int[] data = new int[10000000];  

 

// Инициализировать массив данных положительными значениями,  

for (int i=0; i < data.Length; i++) data[i] = i;  

 

//А теперь ввести в массив данных ряд отрицательных значений,  

data[1000] = -1;  

data [14000] = -2;  

data[15000] = -3;  

data[676000] = -4;  

data[8024540] = -5;  

data [9908000] = -6;  

 

// Использовать запрос PLINQ для поиска отрицательных значений,  

var negatives = from val in  

data.AsParallel(). WithCancellation(cancelTokSrc.Token)  

where val < 0  

select val;  

 

// Создать задачу для отмены запроса по истечении 100 миллисекунд.  

Task cancelTsk = Task.Factory.StartNew(() => {  

Thread.Sleep(100);  

cancelTokSrc.Cancel();  

});  

try {  

foreach(var v in negatives)  

Console.Write(v + " ");  

} catch(OperationCanceledException exc) {  

Console.WriteLine(exc.Message);  

} catch(AggregateException exc) {  

Console.WriteLine (exc);  

} finally {  

cancelTsk.Wait();  

cancelTokSrc.Dispose();  

cancelTsk.Dispose();  

}  

Console.WriteLine();  

}

}

 

Ниже приведен результат выполнения этой программы. Если запрос отменяется до его завершения, то на экран выводится только сообщение об исключительной ситуации.

 

Запрос отменен с помощью маркера, переданного в метод WithCancellation.

 

 

Другие средства PLINQ

 

Как упоминалось ранее, PLINQ представляет собой довольно крупную подсистему. Это объясняется отчасти той гибкостью, которой обладает PLINQ. В PLINQ доступны и многие другие средства, помогающие подстраивать параллельные запросы под конкретную ситуацию. Так, при вызове метода WithDegreeOfParallelism() можно указать максимальное количество процессоров, выделяемых для обработки запроса, а при вызове метода AsSequential() — запросить последовательное выполнение части параллельного запроса. Если вызывающий поток, ожидающий результатов от цикла foreach, не требуется блокировать, то для этой цели можно воспользоваться методом ForAll(). Все эти методы определены в классе ParallelEnumerable. А в тех случаях, когда PLINQ должен по умолчанию поддерживать последовательное выполнение, можно воспользоваться методом WithExecutionMode(), передав ему в качестве параметра признак ParallelExecutionMode.ForceParallelism.

 

 

Вопросы эффективности PLINQ

 

Далеко не все запросы выполняются быстрее только потому, что они распараллелены. Как пояснялось ранее в отношении TPL, издержки, связанные с созданием параллельных потоков и управлением их исполнением, могут "перекрыть" все преимущества, которые дает распараллеливание. Вообще говоря, если источник данных оказывается довольно мелким, а требующаяся обработка данных — очень короткой, то внедрение параллелизма может и не привести к ускорению обработки запроса. Поэтому за рекомендациями по данному вопросу следует обращаться к информации корпорации Microsoft.

 


Дата добавления: 2019-02-12; просмотров: 257; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!