W dobie wielordzeniowych procesorów, umiejętność programowania współbieżnego jest niezwykle istotna. Scenariusz programowania synchronicznego, w którym wszystko wkładamy w jeden wątek i kolejkujemy może spowodować, że nasza aplikacja będzie funkcjonować gorzej od konkurencji. Dobrym tego przykładem są aplikacje operujące na żądaniach sieciowych. Przykładowo aplikacja mobilna może na starcie wymagać pobrania konfiguracji, ściągnięcia informacji na ekran typu "home", czy też aktywacji opcji auto-logowania...
Sztuka programowania 2953 dni, 18 godzin, 4 minuty temu 371 źrodło rozwiń
W ostatnich dwóch wpisach pokazałem zasady działania modelu aktor. W kolejnych postach będę korzystał już z Akka.net zamiast pseudokodu. Dzisiaj czysty opis podstaw API – bez konkretnego problemu do rozwiązania. Akka.net można zainstalować w formie pakietu Nuget: Install-Package Akka
Programowanie rozproszone 3283 dni, 17 godzin, 4 minuty temu 289 źrodło rozwiń
W ostatnim wpisie przedstawiłem zasadę działania modelu aktor. Zachęcam do przeczytania poprzedniego wpisu ponieważ dzisiaj skupię się na przykładzie, a nie podstawach teoretycznych. Jeśli poprzedni wpis nie był do końca zrozumiały, zachęcam do przeanalizowania przykładu z tego wpisu i potem powrócenia do poprzedniego postu – wtedy myślę, że wiele zagadnień będzie prostsze w zrozumieniu.
Programowanie rozproszone 3285 dni, 39 minut temu 189 źrodło rozwiń
Aktor jest modelem budowania aplikacji wielowątkowych. Powstał w celu ułatwienia synchronizacji między różnymi wątkami. Programiści piszący aplikacje wielowątkowe zwykle korzystają z klasycznych blokad (lock) w celu opisania sekcji krytycznej. W wielu sytuacjach jest to najlepszy i najprostszy sposób. Niestety dla dużych i skomplikowanych systemów, utrzymywanie takiego kodu jest bardzo trudne, mozolne i niezwykłe podatne na powstanie deadlock lub livelock.
Programowanie rozproszone 3289 dni, 1 godzinę, 29 minut temu 300 źrodło rozwiń
Coraz więcej API dostarcza asynchroniczne wersje metod. Niektóre z nich, idą o krok dalej i w ogóle nie posiadają synchronicznej wersji. Załóżmy, że zewnętrzna biblioteka ma następującą metodę: async Task
Programowanie rozproszone 3291 dni, 22 godziny, 31 minut temu 316 źrodło rozwiń
Tworząc nowe zadania (wątki) za pomocą TPL, możemy przekazać parametry AttachedToParent lub DenyChildAttach. Określają one, czy wątek powinien być podłączony do rodzica czy nie. W dzisiejszym wpisie postaram wyjaśnić się, czym one różnią się. Parametry definiują relację wątku z nadrzędnym wątkiem. Jeśli wątek A, tworzy kolejny wątek B, wtedy za pomocą powyższych wartości możemy określić relacje wątku B z A. Spróbujmy zatem wyjaśnić jak ta relacja wpływa na...
Programowanie rozproszone 3305 dni, 12 godzin, 45 minut temu 67 źrodło rozwiń
W .NET 4.5 pojawiła się metoda Task.Run. Z przyzwyczajenia jednak przez długi czas używałem tylko Task.Factory.StartNew. Obie metody służą do stworzenia nowego wątku i natychmiastowego jego uruchomienia. Sposób wywołania wygląda bardzo podobnie...
Programowanie rozproszone 3305 dni, 12 godzin, 45 minut temu 283 źrodło rozwiń
Zrównoleglenie danego algorytmu to jeszcze nie koniec wyzwań. Pytanie jakie należy postawić, to jak wiele stworzyć wątków? Musimy wziąć pod uwagę synchronizacje i problemy z tym związane. Jeśli mamy tylko 4 procesory, wtedy tworzenie więcej niż 4 wątków nie przyśpieszy obliczeń, jeśli wszystkie one zawsze będą zajęte. Tworzenie większej liczy wątków niż CPU, ma sens wyłącznie jak część z nich musi czekać na jakieś dane i tym samym, nie wykorzystują one w pełni cykli CPU. Liczba wątków, zależy od tego j...
Sztuka programowania 4000 dni, 1 godzinę, 12 minut temu 98 źrodło rozwiń
W .NET istnieje metoda do wykonywania pętli równolegle. Pisałem ogólne o niej kilka miesięcy temu. Temat jest jednak dużo bardziej skomplikowany i z pewnością należy zrozumieć różne podejścia do problemu. Przed zrównolegleniem pętli, należy zastanowić się czy na prawdę przyniesie to pozytywne efekty. Złe rozpoznanie przypadku spowoduje znaczącą degradację wydajności. Zastanówmy się na co należy zwracać uwagę:Czy poszczególne elementy tablicy można przetwarzać w sposób bezpieczny (thread-safe). Jeśli nie...
Sztuka programowania 4012 dni, 12 godzin, 35 minut temu 168 źrodło rozwiń
Kiedyś pisałem już o false sharing. Jeśli problem nie jest znany, najpierw zachęcam do przeczytania tego wpisu, ponieważ nie będę tutaj pisał o teoretycznych zagadnieniach: http://www.pzielinski.com/?p=1489 Oprócz wyjaśnienia podstaw, podałem przykład struktury danych składających się z dwóch Int32. Pokazałem również jakie pułapki czekają nas przy pracy z tablicami. To zadziwiające, że kolejność w jakiej przeglądamy tablicę ma tak ogromne znaczenie w wydajności (kod może być nawet kilkakrotnie wolniejs...
Sztuka programowania 4018 dni, 55 minut temu 122 źrodło rozwiń
Często można usłyszeć, że przypisania są zawsze bezpieczne w wielowątkowości i powinniśmy martwić się np. inkrementacją. Jest to prawda dla Int32 ale dla long już nie zawsze. Przykład:internalclass Program { privatestaticlong _x =0; privatestaticvoid Main(string[] args) { Task.Factory.StartNew(Task1); Task.Factory.StartNew(Task2); Thread.Sleep(5000); } privatestaticvoid Task2() { while (true) { Console.WriteLine(_x); } } privat...
Sztuka programowania 4114 dni, 2 godziny, 12 minut temu 137 źrodło rozwiń
W ostatnim poście wspomniałem o minimalnej liczbie wątków. Istnieje również górny próg, określający ile maksymalnie może zostać stworzonych wątków. Zbyt niski próg oraz zła architektura może spowodować bardzo trudny w znalezieniu błąd a mianowicie deadlock. Wyobraźmy sobie następującą sekwencję zdarzeń:Wątek T0 (lub główny, nie ma znaczenia) dodaje zadanie do puli.Stworzone zadanie tworzy n nowych zadań.T0 czeka aż wszystkie n zadań zostanie wykonanych (wait). Następnie przyjmijmy, że w tych n wątkach, ...
Sztuka programowania 4171 dni, 4 godziny, 27 minut temu 122 źrodło rozwiń
Pula wątków to specjalny mechanizm zaimplementowany w CLR, mający na celu ponowne używanie tych samych wątków. W dzisiejszym wpisie chciałbym wyjaśnić co to jest optymalna liczba wątków i jaki ona ma wpływ na wydajność. Rozważmy następujący kod:internalclass Program { publicstaticvoid Main() { for (int i =0; i
Sztuka programowania 4174 dni, 3 godziny, 52 minuty temu 169 źrodło rozwiń
Dzisiaj bardzo krótka notka, mająca na celu przestrzec przed modyfikacją jakichkolwiek właściwości wątku, który pochodzi z puli. Bardzo łatwo zmienić jego stan poprzez ustawienie nowego priorytetu albo zmianę kultury. Inny przykład to TLS o którym już pisałem na blogu. Dlaczego jest to tak złe?privatevoid Run() { Thread.CurrentThread.Priority = ThreadPriority.Highest; } Musimy zdać sobie sprawę, że takowe wątki wyłącznie wypożyczamy. Ktoś na forum porównał to do wypożyczalni samochodów. Gdy wypożycz...
Sztuka programowania 4177 dni, 11 godzin, 19 minut temu 68 źrodło rozwiń
Dzisiaj zajmiemy się kolejnym wzorcem przeznaczonym dla środowiska wielowątkowego. W dokumentacji\artykułach możemy go spotkać pod nazwą “condition pattern”. Załóżmy, że jeden wątek musi sprawdzić pewien warunek aby móc wykonać jakąś pracę. Innymi słowy, mamy współdzielony zestaw zmiennych, modyfikowanych przez różne wątki. Jeden z wątków może wykonać swój kod wyłącznie, gdy te współdzielone zmienne spełnią jakiś warunek. W jaki sposób moglibyśmy podejść do problemu? Najprostszym rozwiązaniem byłaby pęt...
Programowanie rozproszone 4179 dni, 18 godzin, 17 minut temu 168 źrodło rozwiń
W ostatnim wpisie pokazałem dostępne bloki buforujące. Dzisiaj zajmiemy się prostym przykładem, który jest bardziej praktyczny od tego przedstawionego w poprzednim poście. Załóżmy, że piszemy system, który składa się z kilku wątków przetwarzających. Każdy z nich pełni rolę konsumenta – przetwarza dane. Chcemy to tak zoptymalizować, aby nowe dane były wysyłane wyłącznie do jak najmniej zajętych węzłów. Oczywiście temat jest bardziej skomplikowany niż może wydawać się, ale dzisiaj pokażemy jak można do te...
Sztuka programowania 4186 dni, 2 godziny, 47 minut temu 29 źrodło rozwiń
Dzisiaj wracamy do tematu TPL Dataflows. W ostatniej części zajęliśmy się m.in. BroadcastBlock, który jest jednym z bloków buforujących. Dla przypomnienia przykład:class Program { privatestaticvoid Main(string[] args) { BroadcastBlock
Sztuka programowania 4189 dni, 3 godziny, 27 minut temu 78 źrodło rozwiń
ReaderWriterLockSlim jest klasą, która ma zastąpić ReadWriterLock, znanego ze starych wersji framework’a. Ale zacznijmy od początku… Dlaczego zwykły lock nie zawsze jest wystarczający? ReaderWriterLockSlim pracuje w trzech trybach:mutual lock – inaczej writer lock. Wyłącznie jedna taka blokada może zostać nadana. Jest to typowy lock i należy z niego korzystać, gdy modyfikujemy dane. shared (reader) lock – wiele wątków może mieć dostęp do tych samych danych. Można nadać wiele shared lock, pod warunkiem, ...
Sztuka programowania 4192 dni, 4 godziny, 23 minuty temu 80 źrodło rozwiń
Klasa Monitor to chyba najpopularniejszy, najłatwiejszy i często najlepszy sposób synchronizacji danych w .NET. Większość programistów używa słowa kluczowego lock zamiast bezpośrednio Monitor.Enter. W większości przypadków jest to poprawne i zdecydowanie najbardziej przejrzyste. Dzisiaj chciałbym przyjrzeć się kilku sposobom konstrukcji Monitor.Enter\MonitorExit. Pierwszy, zdecydowanie najgorszy to:Monitor.Enter(_sync); // sekcja krytyczna tutaj Monitor.Exit(_sync); W powyższym kodzie brakuje obsługi...
Sztuka programowania 4195 dni, 4 godziny, 9 minut temu 143 źrodło rozwiń
W ostatnim poście zajęliśmy się wprowadzeniem do TPL Dataflows. Użyliśmy ActionBlock do implementacji wzorca producent\konsument. Dzisiaj dołączymy kolejne bloki, aby pokazać na czym polega tworzenie współbieżnych algorytmów w TPL. ActionBlock przetwarzał wyłącznie dane – nie zwracał żadnego rezultatu. Innymi słowy, przyjmował parametry wejściowe ale zwracał wyłącznie void. TransformBlock implementuje zarówno ITargetBlock jak i ISourceBlock – stanowi również źródło danych. Rozważmy przykład:privatestati...
Programowanie rozproszone 4201 dni, 3 godziny, 47 minut temu 65 źrodło rozwiń