Ниже приведена форма объявления метода WithCancellation()
:
public static ParallelQuery WithCancellation (
this ParallelQuery 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.
ГЛАВА 25 Коллекции, перечислители и итераторы
В этой главе речь пойдет об одной из самых важных составляющих среды .NET Framework: коллекциях. В C# коллекция представляет собой совокупность объектов. В среде .NET Framework имеется немало интерфейсов и классов, в которых определяются и реализуются различные типы коллекций. Коллекции упрощают решение многих задач программирования благодаря тому, что предлагают готовые решения для создания целого ряда типичных, но порой трудоемких для разработки структур данных. Например, в среду .NET Framework встроены коллекции, предназначенные для поддержки динамических массивов, связных списков, стеков, очередей и хеш-таблиц. Коллекции являются современным технологическим средством, заслуживающим пристального внимания всех, кто программирует на С#.
Читать дальше