ROZDZIAŁ 3. Podstawy przetwarzania równoległego

24

Transcript of ROZDZIAŁ 3. Podstawy przetwarzania równoległego

Page 1: ROZDZIAŁ 3. Podstawy przetwarzania równoległego
Page 2: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

Tytuł oryginału: Concurrency in C# Cookbook

Tłumaczenie: Lech Lachowski

ISBN: 978-83-283-2990-4

© 2017 Helion S.A.

Authorized Polish translation of the English edition Concurrency in C# Cookbook, ISBN 9781449367565 © 2014 Stephen Cleary

This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same.

All rights reserved. No part of this book may be reproduced or transmitted in any formor by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher.

Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji.

Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli.

Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani zaich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce.

Wydawnictwo HELIONul. Kościuszki 1c, 44-100 GLIWICEtel. 32 231 22 19, 32 230 98 63e-mail: [email protected]: http://helion.pl (księgarnia internetowa, katalog książek)

Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/wspcre.zip

Drogi Czytelniku!Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/wspcreMożesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.

Printed in Poland.

• Kup książkę• Poleć książkę • Oceń książkę

• Księgarnia internetowa• Lubię to! » Nasza społeczność

Page 3: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

5

Spis treści

Przedmowa ........................................................................................ 9

1. Współbieżność: przegląd .................................................................. 151.1. Wprowadzenie do współbieżności 151.2. Wprowadzenie do programowania asynchronicznego 181.3. Wprowadzenie do programowania równoległego 231.4. Wprowadzenie do programowania reaktywnego (Rx) 271.5. Wprowadzenie do przepływów danych 291.6. Wprowadzenie do programowania wielowątkowego 321.7. Kolekcje dla aplikacji współbieżnych 331.8. Nowoczesne projektowanie 331.9. Podsumowanie informacji na temat kluczowych technologii 34

2. Podstawy async ................................................................................ 372.1. Wstrzymanie na określony czas 382.2. Zwracanie wykonanych zadań 402.3. Raportowanie postępu 422.4. Oczekiwanie na wykonanie zestawu zadań 432.5. Oczekiwanie na wykonanie jakiegokolwiek zadania 462.6. Przetwarzanie wykonanych zadań 482.7. Unikanie kontekstu dla kontynuacji 512.8. Obsługa wyjątków z metod async typu Task 532.9. Obsługa wyjątków z metod async typu void 55

Poleć książkęKup książkę

Page 4: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

6 Spis treści

3. Podstawy przetwarzania równoległego ............................................. 593.1. Równoległe przetwarzanie danych 603.2. Równoległa agregacja 623.3. Równoległe wywołanie 633.4. Równoległość dynamiczna 653.5. Parallel LINQ 67

4. Podstawy przepływu danych ............................................................. 694.1. Łączenie bloków 704.2. Propagowanie błędów 724.3. Usuwanie połączeń między blokami 744.4. Ograniczanie pojemności bloków 754.5. Przetwarzanie równoległe

za pomocą bloków przepływu danych 764.6. Tworzenie niestandardowych bloków 77

5. Podstawy Rx ..................................................................................... 815.1. Konwersja zdarzeń .NET 825.2. Wysyłanie powiadomień do kontekstu 855.3. Grupowanie danych zdarzeń za pomocą okienek i buforów 875.4. Ujarzmianie strumieni zdarzeń za pomocą ograniczania

przepływu i próbkowania 905.5. Limity czasu 92

6. Testowanie ....................................................................................... 976.1. Testy jednostkowe metod async 986.2. Testy jednostkowe metod async,

które powinny zakończyć się niepowodzeniem 1006.3. Testy jednostkowe metod async void 1026.4. Testy jednostkowe siatek przepływu danych 1046.5. Testy jednostkowe strumieni obserwowalnych Rx 1056.6. Testy jednostkowe strumieni obserwowalnych Rx

za pomocą atrapy harmonogramu 108

Poleć książkęKup książkę

Page 5: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

Spis treści 7

7. Interoperacyjność ........................................................................... 1137.1. Metody opakowujące async dla metod „async”

ze zdarzeniami „Completed” 1137.2. Metody opakowujące async dla metod „Begin/End” 1167.3. Metody opakowujące async dla dowolnych operacji

lub zdarzeń 1177.4. Metody opakowujące async dla kodu równoległego 1197.5. Metody opakowujące async

dla strumieni obserwowalnych Rx 1207.6. Metody opakowujące strumieni obserwowalnych Rx

dla kodu asynchronicznego 1227.7. Strumienie obserwowalne Rx i siatki przepływu danych 124

8. Kolekcje ......................................................................................... 1278.1. Niemutowalne stosy i kolejki 1308.2. Listy niemutowalne 1338.3. Zbiory niemutowalne 1358.4. Słowniki niemutowalne 1378.5. Słowniki bezpieczne wątkowo 1408.6. Kolejki blokujące 1428.7. Stosy i multizbiory blokujące 1458.8. Kolejki asynchroniczne 1478.9. Stosy i multizbiory asynchroniczne 1508.10. Kolejki blokujące/asynchroniczne 153

9. Anulowanie .................................................................................... 1599.1. Wysyłanie żądań anulowania 1609.2. Reagowanie na żądania anulowania poprzez odpytywanie 1639.3. Anulowanie z powodu przekroczenia limitu czasu 1659.4. Anulowanie kodu async 1679.5. Anulowanie kodu równoległego 1689.6. Anulowanie kodu reaktywnego 1709.7. Anulowanie siatek przepływu danych 1729.8. Wstrzykiwanie żądań anulowania 1739.9. Współdziałanie z innymi systemami anulowania 175

Poleć książkęKup książkę

Page 6: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

8 Spis treści

10. Przyjazne funkcyjnie programowanie obiektowe ............................. 17910.1. Interfejsy async i dziedziczenie 18010.2. Konstruowanie async: fabryki 18110.3. Konstruowanie async:

wzorzec inicjowania asynchronicznego 18410.4. Właściwości async 18810.5. Zdarzenia async 19210.6. Usuwanie async 195

11. Synchronizacja ................................................................................ 20111.1. Blokady 20711.2. Blokady async 20911.3. Sygnały blokujące 21211.4. Sygnały async 21311.5. Ograniczanie współbieżności 215

12. Planowanie .................................................................................... 21912.1. Planowanie pracy dla puli wątków 21912.2. Wykonywanie kodu za pomocą dyspozytora zadań 22112.3. Planowanie kodu równoległego 22412.4. Synchronizacja przepływu danych

z wykorzystaniem dyspozytorów 225

13. Scenariusze .................................................................................... 22713.1. Inicjowanie współdzielonych zasobów 22713.2. Odroczona ewaluacja Rx 22913.3. Asynchroniczne wiązanie danych 231

Skorowidz ...................................................................................... 237

Poleć książkęKup książkę

Page 7: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

59

ROZDZIAŁ 3.

Podstawy przetwarzania równoległego

W tym rozdziale omówimy wzorce dla programowania równoległego. Progra-mowanie równoległe jest stosowane do podzielenia ograniczonych możliwo-ściami obliczeniowymi fragmentów pracy i rozdzielenia ich na wiele wątków.Przedstawione poniżej receptury przetwarzania równoległego uwzględniają jedy-nie zadania uzależnione od wydajności procesora. Jeśli masz naturalnie asyn-chroniczne operacje (takie jak zadania ograniczone możliwościami we-wy),które chcesz wykonywać równolegle, zapoznaj się z rozdziałem 2., a w szczegól-ności z recepturą 2.4.

Abstrakcje przetwarzania równoległego omówione w tym rozdziale są częściąbiblioteki zadań równoległych (ang. Task Parallel Library — TPL). Jest onawbudowana we framework .NET, ale nie jest dostępna na wszystkich plat-formach (zobacz tabela 3.1):

Tabela 3.1. Wsparcie platform dla biblioteki TPL

Platforma Wsparcie dla przetwarzania równoległego

.NET 4.5

.NET 4.0

Mono iOS/Droid

Windows Store

Windows Phone Apps 8.1

Windows Phone SL 8.0

Windows Phone SL 7.1

Silverlight 5

Poleć książkęKup książkę

Page 8: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

60 Rozdział 3. Podstawy przetwarzania równoległego

3.1. Równoległe przetwarzanie danych

ProblemMamy kolekcję danych i musimy wykonać tę samą operację na każdym elemen-cie tych danych. Ta operacja jest ograniczona możliwościami obliczeniowymiprocesora i może zająć trochę czasu.

RozwiązanieTyp Parallel zawiera metodę ForEach specjalnie przeznaczoną do tego celu.Kod przedstawiony w tym przykładzie przyjmuje kolekcję macierzy i odwracaje wszystkie:

void RotateMatrices(IEnumerable<Matrix> matrices, float degrees){ Parallel.ForEach(matrices, matrix => matrix.Rotate(degrees));}

W niektórych sytuacjach będziemy chcieli zatrzymać pętlę wcześniej, na przykładprzy napotkaniu nieprawidłowej wartości. Poniższy kod odwraca każdą macierz,ale jeśli zostanie napotkana nieprawidłowa macierz, pętla zostanie przerwana:

void InvertMatrices(IEnumerable<Matrix> matrices){ Parallel.ForEach(matrices, (matrix, state) => { if (!matrix.IsInvertible) state.Stop(); else matrix.Invert(); });}

Bardziej powszechną sytuacją jest potrzeba posiadania możliwości anulowaniarównoległej pętli. Różni się to od zatrzymania pętli. Pętla jest zatrzymywanaz wewnątrz pętli, a anulowanie odbywa się z zewnątrz pętli. Przykładowo CancellationTokenSource może być anulowany za pomocą przycisku anulowania, co

spowoduje anulowanie równoległej pętli, takiej jak ta:

void RotateMatrices(IEnumerable<Matrix> matrices, float degrees, CancellationToken token){ Parallel.ForEach(matrices,

Poleć książkęKup książkę

Page 9: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

3.1. Równoległe przetwarzanie danych 61

new ParallelOptions { CancellationToken = token }, matrix => matrix.Rotate(degrees));}

Należy pamiętać o tym, że każde zadanie równoległe może działać w innym wątku,dlatego każdy współdzielony stan musi być chroniony. Poniższy kod odwracakażdą macierz i zlicza macierze, które nie mogły zostać odwrócone:

// Uwaga: to nie jest najbardziej efektywna implementacja.// To tylko przykład użycia blokady do ochrony współdzielonego stanu.int InvertMatrices(IEnumerable<Matrix> matrices){ object mutex = new object(); int nonInvertibleCount = 0; Parallel.ForEach(matrices, matrix => { if (matrix.IsInvertible) { matrix.Invert(); } else { lock (mutex) { ++nonInvertibleCount; } } }); return nonInvertibleCount;}

DyskusjaMetoda Parallel.ForEach umożliwia przetwarzanie równoległe na sekwencjiwartości. Podobnym rozwiązaniem jest technologia PLINQ (ang. Parallel LINQ).PLINQ zapewnia prawie te same możliwości za pomocą składni podobnej doLINQ. Jedną z różnic pomiędzy Parallel i PLINQ jest to, że PLINQ zakłada moż-liwość wykorzystania wszystkich rdzeni na komputerze, podczas gdy Parallelbędzie dynamicznie reagować na zmieniające się warunki procesora.

Parallel.ForEach to równoległa pętla foreach. Jeśli trzeba wykonać równoległąpętlę for, klasa Parallel obsługuje również metodę Parallel.For. Ta metodajest szczególnie użyteczna, jeśli masz wiele tablic danych, z których wszystkiewykorzystują ten sam indeks.

Poleć książkęKup książkę

Page 10: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

62 Rozdział 3. Podstawy przetwarzania równoległego

Zobacz równieżReceptura 3.2 omawia równoległą agregację szeregu wartości, w tym sumi średnich.

Receptura 3.5 opisuje podstawy PLINQ.

Rozdział 9. omawia anulowanie.

3.2. Równoległa agregacja

ProblemNa zakończenie równoległej operacji musimy zagregować wyniki. Przykładamiagregacji są sumy, średnie itp.

RozwiązanieKlasa Parallel obsługuje agregację poprzez koncepcję wartości lokalnych, któresą zmiennymi występującymi lokalnie w ramach równoległej pętli. Oznaczato, że ciało pętli może po prostu uzyskać dostęp do tej wartości bezpośrednio,bez konieczności przejmowania się synchronizacją. Gdy pętla jest gotowa doagregacji wszystkich swoich lokalnych wyników, robi to za pomocą delegatalocalFinally. Należy zwrócić uwagę, że delegat localFinally potrzebuje zsyn-chronizować dostęp do zmiennej, która przechowuje wynik końcowy. Otoprzykład sumy równoległej:

// Uwaga: to nie jest najbardziej efektywna implementacja.// To tylko przykład użycia blokady do ochrony współdzielonego stanu.static int ParallelSum(IEnumerable<int> values){ object mutex = new object(); int result = 0; Parallel.ForEach(source: values, localInit: () => 0, body: (item, state, localValue) => localValue + item, localFinally: localValue => { lock (mutex) result += localValue; }); return result;}

Poleć książkęKup książkę

Page 11: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

3.3. Równoległe wywołanie 63

Parallel LINQ ma bardziej naturalną możliwość obsługi agregacji niż klasaParallel:

static int ParallelSum(IEnumerable<int> values){ return values.AsParallel().Sum();}

No dobrze, to był cios poniżej pasa, ponieważ PLINQ ma wbudowaną obsługęwielu typowych operatorów (na przykład Sum). PLINQ oferuje również ogólnąobsługę agregacji poprzez operator Aggregate:

static int ParallelSum(IEnumerable<int> values){ return values.AsParallel().Aggregate( seed: 0, func: (sum, item) => sum + item );}

DyskusjaJeśli używasz już klasy Parallel, możesz chcieć skorzystać z jej wsparcia dlaagregacji. W przeciwnym razie wsparcie PLINQ jest w większości scenariuszybardziej ekspresyjne i ma krótszy kod.

Zobacz równieżReceptura 3.5 omawia podstawy PLINQ.

3.3. Równoległe wywołanie

ProblemMamy wiele metod wywoływanych równolegle; metody te są (w większości) nie-zależne od siebie.

RozwiązanieKlasa Parallel zawiera prostą składową Invoke, która jest przeznaczona dla tegoscenariusza. Oto przykład kodu, który dzieli tablicę na pół i przetwarza każdąpołówkę niezależnie:

Poleć książkęKup książkę

Page 12: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

64 Rozdział 3. Podstawy przetwarzania równoległego

static void ProcessArray(double[] array){ Parallel.Invoke( () => ProcessPartialArray(array, 0, array.Length / 2), () => ProcessPartialArray(array, array.Length / 2, array.Length) );}

static void ProcessPartialArray(double[] array, int begin, int end){ // Przetwarzanie wymagające obliczeniowo…}

Do metody Parallel.Invoke można również przekazać tablicę delegatów, jeśliliczba wywołań nie jest znana aż do czasu wykonywania:

static void DoAction20Times(Action action){ Action[] actions = Enumerable.Repeat(action, 20).ToArray(); Parallel.Invoke(actions);}

Metoda Parallel.Invoke obsługuje anulowanie podobnie jak inne składoweklasy Parallel:

static void DoAction20Times(Action action, CancellationToken token){ Action[] actions = Enumerable.Repeat(action, 20).ToArray(); Parallel.Invoke(new ParallelOptions { CancellationToken = token },actions);}

DyskusjaMetoda Parallel.Invoke jest doskonałym rozwiązaniem dla prostych wywołańrównoległych. Nie sprawdzi się jednak zbyt dobrze, jeśli chcesz wywołać akcjędla każdego elementu danych wejściowych (zamiast niej należy użyć metodyParallel.ForEach) lub jeśli każda akcja generuje jakieś dane wyjściowe (wtedynależy skorzystać z Parallel LINQ).

Zobacz równieżReceptura 3.1 opisuje metodę Parallel.ForEach, która wywołuje akcję dlakażdego elementu danych.

Receptura 3.5 omawia Parallel LINQ.

Poleć książkęKup książkę

Page 13: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

3.4. Równoległość dynamiczna 65

3.4. Równoległość dynamiczna

ProblemMamy bardziej złożoną sytuację równoległą, w której struktura i liczba równo-ległych zadań zależą od informacji znanych dopiero w czasie wykonywania pro-gramu.

RozwiązanieBiblioteka zadań równoległych jest skoncentrowana wokół typu Task. KlasaParallel i technologia Parallel LINQ zapewniają tylko wygodne funkcje opa-kowujące dla tego typu. Gdy potrzebna jest równoległość dynamiczna, naj-łatwiej jest użyć typu Task bezpośrednio.

Oto jeden z przykładów, w którym dla każdego węzła binarnego drzewa trze-ba wykonać kosztowne przetwarzanie. Struktura drzewa nie będzie znana ażdo czasu wykonywania, dlatego jest to dobry scenariusz dla równoległości dy-namicznej. Metoda Traverse przetwarza bieżący węzeł, a następnie tworzy dwazadania podrzędne, po jednym dla każdej gałęzi pod węzłem (w tym przykła-dzie zakładamy, że węzły nadrzędne muszą być przetwarzane przed podrzęd-nymi). Metoda ProcessTree rozpoczyna przetwarzanie poprzez utworzenie za-dania nadrzędnego najwyższego poziomu i czekanie na jego zakończenie:

void Traverse(Node current){ DoExpensiveActionOnNode(current); if (current.Left != null) { Task.Factory.StartNew(() => Traverse(current.Left), CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Default); } if (current.Right != null) { Task.Factory.StartNew(() => Traverse(current.Right), CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Default); }}

Poleć książkęKup książkę

Page 14: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

66 Rozdział 3. Podstawy przetwarzania równoległego

public void ProcessTree(Node root){ var task = Task.Factory.StartNew(() => Traverse(root), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); task.Wait();}

Jeśli nie masz sytuacji typu zadanie nadrzędne – podrzędne, możesz zaplanować,aby każde zadanie było uruchamiane po innym, stosując kontynuację zadań.Kontynuacja jest osobnym zadaniem, które jest wykonywane, gdy pierwotnezadanie zostanie zakończone:

Task task = Task.Factory.StartNew( () => Thread.Sleep(TimeSpan.FromSeconds(2)), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);Task continuation = task.ContinueWith( t => Trace.WriteLine("Zadanie zosta o wykonane" ), CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default);// Argument "t" dla kontynuacji jest taki sam jak "task".

DyskusjaPowyższy przykładowy kod wykorzystuje właściwości CancellationToken.Noneoraz TaskScheduler.Default. Tokeny anulowania zostały opisane w recep-turze 9.2, a dyspozytory zadań w recepturze 12.3. Zawsze dobrym pomysłemjest bezpośrednio określić TaskScheduler używany przez metody StartNewi ContinueWith.

Ten układ zadań nadrzędnych i podrzędnych jest typowy dla równoległości dy-namicznej. Nie jest jednak wymagany. Można również przechowywać każde no-we zadanie w wątkowo bezpiecznej kolekcji, a następnie za pomocą Task.WaitAllpoczekać na zakończenie ich wszystkich.

Używanie typu Task dla przetwarzania równoległego całkowicieróżni się od wykorzystania Task dla przetwarzania asynchro-nicznego. Zobacz poniżej.

Poleć książkęKup książkę

Page 15: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

3.5. Parallel LINQ 67

W programowaniu równoległym typ Task służy dwóm celom: może być zada-niem równoległym lub zadaniem asynchronicznym. Zadania równoległe mogąwykorzystywać składowe blokujące, takie jak Task.Wait, Task.Result, Task.WaitAll i Task.WaitAny. Często używają również AttachedToParent do tworzenia

między zadaniami relacji nadrzędne – podrzędne. Zadania równoległe po-winny być tworzone za pomocą metod Task.Run lub Task.Factory.StartNew.

W przeciwieństwie do tego, w przypadku zadań asynchronicznych powinno sięunikać składowych blokujących i preferować użycie await, Task.WhenAll i Task.WhenAny. Zadania asynchroniczne nie używają AttachedToParent, ale mogą for-mować dorozumiany rodzaj relacji nadrzędne – podrzędne poprzez oczeki-wanie na kolejne zadanie.

Zobacz równieżReceptura 3.3 omawia równoległe wywoływanie sekwencji metod, gdy wszystkiete metody są znane przy rozpoczynaniu pracy równoległej.

3.5. Parallel LINQ

ProblemMamy do wykonania przetwarzanie równoległe na sekwencji danych, tworzącekolejną sekwencję danych lub podsumowanie tych danych.

RozwiązanieWiększość programistów jest zaznajomiona z technologią LINQ, którą możnawykorzystać do napisania opartych na modelu pull obliczeń na sekwencjach. Pa-rallel LINQ (PLINQ) rozszerza to wsparcie LINQ o przetwarzanie równoległe.

PLINQ dobrze sprawdza się w scenariuszach strumieniowych, gdy mamy se-kwencję danych wejściowych i generujemy sekwencję danych wyjściowych.Oto prosty przykład, w którym po prostu mnożymy przez dwa każdy elementw sekwencji (rzeczywiste scenariusze będą znacznie bardziej wymagające oblicze-niowo niż proste mnożenie):

static IEnumerable<int> MultiplyBy2(IEnumerable<int> values){

Poleć książkęKup książkę

Page 16: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

68 Rozdział 3. Podstawy przetwarzania równoległego

return values.AsParallel().Select(item => item * 2);}

Ten kod może generować swoje dane wyjściowe w dowolnej kolejności. Jestto ustawienie domyślne dla Parallel LINQ. Można także określić kolejność, którama być zachowana. Poniższy kod jest nadal przetwarzany równolegle, ale za-chowuje oryginalną kolejność:

static IEnumerable<int> MultiplyBy2(IEnumerable<int> values){ return values.AsParallel().AsOrdered().Select(item => item * 2);}

Innym naturalnym wykorzystaniem PLINQ jest równoległe agregowanie lubpodsumowywanie danych. Poniższy kod wykonuje równoległe sumowanie:

static int ParallelSum(IEnumerable<int> values){ return values.AsParallel().Sum();}

DyskusjaKlasa Parallel jest dobra dla wielu scenariuszy, ale kod PLINQ jest prostszy,gdy wykonujemy agregację lub przekształcamy jedną sekwencję w drugą. Należypamiętać, że klasa Parallel jest bardziej przyjazna dla innych procesów w syste-mie niż PLINQ. Jest to szczególnie istotne, jeżeli przetwarzanie równoległeodbywa się na serwerze.

PLINQ zapewnia równoległe wersje wielu różnych operatorów, w tym filtrowania(Where), rzutowania (Select) oraz wielu agregacji, takich jak Sum, Average i bar-dziej ogólna Aggregate. Zasadniczo wszystko, co można zrobić za pomocą zwy-kłego LINQ, można zrobić równolegle za pomocą PLINQ. To sprawia, że PLINQjest doskonałym wyborem, jeśli mamy istniejący kod LINQ, który skorzystałby nawykonywaniu równoległym.

Zobacz równieżReceptura 3.1 opisuje sposób użycia klasy Parallel do wykonywania kodu dlakażdego elementu w sekwencji.

Receptura 9.5 omawia sposób anulowania zapytań PLINQ.

Poleć książkęKup książkę

Page 17: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

237

Skorowidz

A

agregacja, 62, 68anulowanie, 159, 165

kodu async, 167kodu reaktywnego, 170kodu równoległego, 168siatek przepływu danych, 172

APM, Asynchronous ProgrammingModel, 116

async, 37anulowanie kodu, 167blokady, 209interfejsy, 180sygnały, 213testy jednostkowe, 98usuwanie, 195zdarzenia, 192

asynchroniczne wiązanie danych, 231

B

bibliotekaAsyncEx, 231Microsoft.Bcl.Async, 166Nito.AsyncEx, 114, 192przepływu danych, 29, 69rozszerzeń reaktywnych, 81, 223Rx, 81TPL, 70

blokprzepływu danych, 30try-catch, 53

blokada, 207Monitor, 208ReaderWriterLockSlim, 208SpinLock, 208

blokady async, 209, 211bloki

niestandardowe, 77przepływu danych, 70, 74

bufor, 87

C

CancellationToken, 172, 175

D

delegat localFinally, 62dyspozytor, scheduler, 109, 219

Rx, 223TaskScheduler, 222

dyspozytory zadań, 221dziedziczenie, 180

Poleć książkęKup książkę

Page 18: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

238 Skorowidz

E

EAP, Event-based AsynchronousPattern, 113

ewaluacja Rx, 229

F

fabryka, 182FIFO, first-in, first-out, 132framework .NET, 34funkcja callback, 118

G

gorący strumień obserwowalny, 28grupowanie danych zdarzeń, 87

I

inicjowanie współdzielonych zasobów,227

instrukcja lock, 208interfejs IObservable<T>, 105interfejsy async, 180interoperacyjność, 113

K

klasaCancellationTokenSource, 162ExpectedExceptionAttribute, 100Parallel, 62, 68ParallelOptions, 168

kolejka, 130FIFO, 132

kolejkiasynchroniczne, 147blokujące, 142blokujące/asynchroniczne, 153

kolekcje, 127bezpieczne wątkowo, 128, 207dla aplikacji współbieżnych, 33

niemutowalne, 35, 127producent-konsument, 128współbieżne, 35

komunikacja, 201konstruktory, 182kontekst synchronizacji, 86kontynuacja zadań, 66konwersja właściwości synchronicznej,

190konwersja zdarzeń .NET, 82koordynowanie działania bloków, 226

L

LIFO, last-in, first-out, 131limity czasu, 92LINQ, 27, 67lista, 133

Ł

łączenie bloków, 70przepływu danych, 74

M

metodaAddOrUpdate, 140AdvanceBy, 111AdvanceTo, 111AggregateException.Flatten, 73Assert.ThrowsException, 101ConfigureAwait, 52CreateLinkedTokenSource, 174DataflowBlock.Encapsulate, 78Delay, 38DownloadStringTaskAsync, 114, 115Encapsulate, 78, 79Execute, 55ForEach, 60FromAsync, 117, 123InitializeAsync, 182

Poleć książkęKup książkę

Page 19: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

Skorowidz 239

Link, 71LinkTo, 74LogicalGetData, 234LogicalSetData, 234Observable.FromEvent, 84OnNext, 82OrderByCompletion, 51OutputAvailableAsync, 149Parallel.Invoke, 225ProcessTree, 65StartAsync, 123Task.Delay, 38, 39Task.FromResult, 41Task.Run, 120, 220Task.Wait, 99Task.WhenAll, 44Task.WhenAny, 46TaskScheduler.FromCurrentSynchro

nizationContext, 223ThrowIfCancellationRequested, 165ThrowsException, 101ToObservable, 123TryGetValue, 141

metodyasync, 98async typu Task, 53async typu void, 55, 102opakowujące async, 113, 116–120opakowujące strumieni

obserwowalnych Rx, 122rozszerzające, 51testów jednostkowych, 98typu Parallel, 168

migawki, 33model

pull, 28push, 28

multizbioryasynchroniczne, 150blokujące, 145

N

niemutowalnekolejki, 130listy, 133słowniki, 137stosy, 130zbiory, 135

O

obiekty oczekiwalne, 20obietnica, 17obsługa

przepływu danych, 37, 69wyjątków, 53, 55

ochrona danych, 201oczekiwane zadania, 48oczekiwanie na wykonanie, 43, 46odpytywanie, 163odroczona ewaluacja Rx, 229ograniczanie

pojemności bloków, 75przepływu, 90współbieżności, 215

okienko, 87opakowywanie APM, 116opcja

BoundedCapacity, 77MaxDegreeOfParallelism, 76, 77

operacje asynchroniczne, 17, 122operator

Buffer, 88FromAsync, 171Observable.Defer, 230ObserveOn, 85Return, 106Sample, 90SelectMany, 171SingleAsync, 106StartAsync, 171

Poleć książkęKup książkę

Page 20: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

240 Skorowidz

operatorThrottle, 90Throw, 107Timeout, 93Window., 88

P

Parallel LINQ, 67, 169pętla foreach, 134planowanie, 219

kodu równoległego, 224pracy dla puli wątków, 219

platformy, 35, 211PLINQ, Parallel LINQ, 61, 67połączone tokeny anulowania, 174powiadomienia do kontekstu, 85powiadomienie, 20problem z wydajnością, 52programowanie

asynchroniczne, 17, 18obiektowe, 179reaktywne, Rx, 17, 27równoległe, 23wielowątkowe, 32

projektowanie nowoczesne, 33propagowanie błędów, 72próbkowanie, 90przeciążenie metody, 55przekroczenie limitu czasu, 165przepływ danych, 29, 35, 69przetwarzanie

równoległe, 16, 35, 59, 76, 119wykonanych zadań, 48

pula wątków, 120, 219

R

raportowanie postępu, 42równoległa agregacja, 62

równoległeprzetwarzanie danych, 60wywołanie, 63

równoległość dynamiczna, 65równoważenie obciążenia, 75Rx, Reactive Extensions, 27, 35, 81

S

scenariusze, 227siatka przepływu danych, 104, 124słownik HttpContext.Current.Items, 235słowniki

bezpieczne wątkowo, 140niemutowalne, 137

słowo kluczowe async, 37stan niejawny, 233stos, 130, 145, 150

LIFO, 131struktura danych

kolejka, 131lista, 133stos, 131

strumień obserwowalny Rx, 105, 120,124

gorący, 29zimny, 29

strumień zdarzeń, 90subskrypcja strumienia obserwowalnego,

170sygnał ManualResetEventSlim, 212sygnały

async, 213blokujące, 212

symulowanie zależnościasynchronicznych, 99

synchronizacja, 201przepływu, 225

Poleć książkęKup książkę

Page 21: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

Skorowidz 241

T

TAP, Task-based Asynchronous Pattern,113

TDD, test-driven development, 97technologia

LINQ, 67PLINQ, 61

testowanie, 97obsługi błędów, 102

testy jednostkowe, 98metod async, 100metod async void, 102siatek przepływu danych, 104strumieni obserwowalnych Rx, 105,

108tokeny anulowania, 66TPL, Task Parallel Library, 34, 59TPL Dataflow, 29, 69tworzenie niestandardowych bloków, 77typ

ActionBlock<T>, 153Async

ProducerConsumerQueue<T>,150

AsyncCollection<T>, 151, 153AsyncContext, 103AsyncLazy<T>, 229AsyncManualResetEvent, 215AsyncProducerConsumerQueue<T>

, 145, 148, 155, 156BlockingCollection<T>, 143, 145,

146, 152BufferBlock<T>, 145, 147, 150, 155CallContext, 234CancellationTokenSource, 160ConcurrentDictionary<TKey,

TValue>, 140future, 17ImmutableDictionary<TK,TV>, 139ImmutableHashSet<T>, 136ImmutableList<T>, 134

ImmutableSortedDictionary<TK,TV>,139

ImmutableSortedSet<T>, 136IMyFundamentalType, 185IProgress<T>, 42Lazy<T>, 227List<T>, 134ManualResetEvent, 214NotifyTaskCompletion, 231Progress<T>, 42SemaphoreSlim, 209SynchronizationContext, 57System.Timers.Timer, 83Task, 67Task<T>, 220TaskCompletionSource<T>, 118,

213TaskCompletionSource<TResult>,

114TestScheduler, 110

typy synchronizacjikomunikacja, 201ochrona danych, 201

U

unikanie kontekstu dla kontynuacji, 51usuwanie

async, 195połączeń między blokami, 74

W

wątek wywołujący, 120wątki

konsumentów, 143producentów, 143

wielowątkowość, 16właściwości async, 188, 190właściwość

CancellationToken, 172TaskScheduler.Default, 222

Poleć książkęKup książkę

Page 22: ROZDZIAŁ 3. Podstawy przetwarzania równoległego

242 Skorowidz

wsparcie platformdla blokad asynchronicznych, 211dla współbieżności, 35

współbieżność, 15wstrzykiwanie żądań anulowania, 173wstrzymanie na określony czas, 38wydajność, 52wyjątek

AggregateException, 71, 73InvalidOperationException, 148TrySetException, 115

wyjątki, 53wykonywanie kodu

dyspozytor zadań, 221wysyłanie

powiadomień, 85żądań anulowania, 160

wznawianie w kontekście, 52wzorzec

BeginOperacja, 116EndOperacja, 116inicjowania asynchronicznego, 184OperacjaAsync, 113OperacjaCompleted, 113

Z

zadaniaasynchroniczne, 67równoległe, 67

zakończenie asynchroniczne, 195, 196,199

zbiory niemutowalne, 135zdarzenia

.NET, 82async, 17, 192OperacjaCompleted, 113poleceń, 194powiadomień, 194

zimny strumień obserwowalny, 29

Ż

żądanie anulowania, 160, 163

Poleć książkęKup książkę

Page 24: ROZDZIAŁ 3. Podstawy przetwarzania równoległego