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; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!