Добавить в цитаты Настройки чтения

Страница 441 из 502

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

<b>public static ParallelQuery&lt;TSource&gt;  WithCancellation&lt;TSource&gt; (</b>

<b>                  this ParallelQuery&lt;TSource&gt; source,</b>

<b>                             CancellationToken cancellationToken)</b>

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

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

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

<b>using System;</b>

<b>using System.Linq; </b>

<b>using System.Threading; </b>

<b>using System.Threading.Tasks; </b>

<b>class PLINQCancelDemo { </b>

<b>  static void Main() { </b>

<b>    CancellationTokenSource cancelTokSrc = new CancellationTokenSource(); </b>

<b>    int[] data = new int[10000000]; </b>

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

<b>    for (int i=0; i &lt; data.Length; i++) data[i] = i; </b>

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

<b>    data[1000] = -1; </b>

<b>    data [14000] = -2; </b>

<b>    data[15000] = -3; </b>

<b>    data[676000] = -4; </b>

<b>    data[8024540] = -5; </b>

<b>    data [9908000] = -6; </b>

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

<b>    var negatives = from val in </b>

<b>          data.AsParallel(). WithCancellation(cancelTokSrc.Token) </b>

<b>          where val &lt; 0 </b>

<b>          select val; </b>

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

<b>    Task cancelTsk = Task.Factory.StartNew(() =&gt; { </b>

<b>              Thread.Sleep(100); </b>

<b>              cancelTokSrc.Cancel(); </b>

<b>    }); </b>

<b>    try { </b>

<b>      foreach(var v in negatives) </b>

<b>        Console.Write(v + &quot; &quot;); </b>

<b>    } catch(OperationCanceledException exc) { </b>

<b>      Console.WriteLine(exc.Message); </b>

<b>    } catch(AggregateException exc) { </b>

<b>      Console.WriteLine (exc); </b>

<b>    } finally { </b>

<b>      cancelTsk.Wait(); </b>

<b>      cancelTokSrc.Dispose(); </b>

<b>      cancelTsk.Dispose(); </b>

<b>    } </b>

<b>    Console.WriteLine(); </b>

<b>  }</b>

<b>}</b>

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

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

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

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