2012-05-10 11 views
12

Delegaci to tylko niektóre z obiektów, które ułatwiają nawiązywanie wątków w .NET reference. Można ich użyć do asynchronicznego wywoływania metody. Jakie inne obiekty istnieją w frameworku 4.5 (lub wcześniejszym), które sprawiają, że korzystanie z wątków jest łatwiejsze lub mniej podatne na błędy?Co .NET 4.5 (lub wcześniejszych) konstruktów wyższego poziomu sprawia, że ​​wątki są łatwiejsze?

Jakie inne abstrakcje ułatwiają współbieżność i wielowątkowość?

Uwaga: to pytanie jest aktualizowane na this.

+4

Delegaci i wydarzenia nie mają nic wspólnego z wątkami, a nie są specyficzne dla .NET 4.5. Proszę wyjaśnić, ponieważ nie mogę powiedzieć, o czym mówisz. –

+0

@JohnSaunders Async Delegaci ułatwiają nawiązywanie wątków; zobacz http://msdn.microsoft.com/en-us/library/22t547yb.aspx – LamonteCristo

+0

Czy zauważyłeś, że asynchroniczne korzystanie z delegatów było w .NET od wersji 1.0? –

Odpowiedz

21

Często odpowiadam na wiele pytań związanych z wielowątkowością i często widzę to samo podstawowe pytanie zadawane na różne sposoby. Przedstawię najczęstsze problemy, jakie widziałem na przestrzeni lat i wyjaśnię, w jaki sposób nowsze technologie ułatwiły rozwiązanie tych problemów.

zamykania nad zmiennej sterującej

nie jest problemem specyficzne przewlekanie, ale użycie gwintowanie zdecydowanie powiększa problem. C# 5.0 rozwiązuje ten problem dla pętli foreach, tworząc nową zmienną dla każdej iteracji. Nie będziesz już musiał tworzyć specjalnej zmiennej dla zamknięć wyrazów lambda. Niestety, pętla for nadal będzie wymagać obsługi specjalną zmienną przechwytywania.

czekając na zadania asynchroniczne wypełnić

.NET 4.0 wprowadzono klasę CountdownEvent który hermetyzuje wiele logiki wymagane czekać na zakończenie wielu zadań. Większość młodszych programistów używała połączeń Thread.Join lub pojedynczego połączenia WaitHandle.WaitAll. Oba mają problemy z skalowalnością. Stary wzorzec miał używać pojedynczego ManualResetEvent i sygnalizować, gdy licznik osiągnie zero. Licznik został zaktualizowany przy użyciu klasy Interlocked. CountdownEvent czyni ten wzór znacznie łatwiejszym. Pamiętaj tylko, aby traktować swoją pracę główną jako pracownika, aby uniknąć subtelnych warunków wyścigu, które mogą wystąpić, gdy jeden pracownik zakończy pracę, zanim wszyscy pracownicy zostaną w kolejce.

. NET 4.0 wprowadził także klasę Task, która może mieć zadania potomne powiązane z nią przez TaskCreationOptions.AttachedToParent. Jeśli zadzwonisz pod numer Task.Wait na rodzica, to będzie czekać na zakończenie wszystkich zadań podrzędnych.

Producent-Konsument

.NET 4.0 wprowadzono klasę BlockingCollection który działa jak normalny kolejce wyjątkiem, że można go zablokować, gdy zbiór jest pusty. Można kolejkować obiekt, wywołując Add i usuwając kolejkę obiektów, wywołując Take. Take bloków, dopóki element nie będzie dostępny. To znacznie upraszcza logikę producenta-konsumenta. Kiedyś programiści próbowali napisać własną klasę blokowania kolejek. Ale jeśli nie wiesz, co robisz, możesz naprawdę to zepsuć ... źle. W rzeczywistości przez najdłuższy czas Microsoft miał przykład blokującej kolejki w dokumentacji MSDN, która sama została poważnie uszkodzona. Na szczęście od tego czasu został usunięty.

Aktualizacja UI z postępu wątku pracownik

Wprowadzenie BackgroundWorker wykonane wydzielenia zadanie tła z aplikacji WinForm dużo łatwiejsze dla początkujących programistów. Główną zaletą jest to, że można zadzwonić pod numer ReportProgress z poziomu obsługi zdarzeń DoWork, a programy obsługi zdarzeń ProgressChanged zostaną automatycznie przełożone na wątek interfejsu użytkownika. Oczywiście każdy, kto śledzi moje odpowiedzi na SO, wie, co myślę o operacjach marszałkowych (poprzez Invoke lub tym podobnych) jako rozwiązanie do aktualizacji interfejsu użytkownika z prostymi informacjami o postępach. Rozrywam go cały czas, ponieważ jest to generalnie okropne podejście. BackgroundWorker nadal zmusza programistę do modelu push (poprzez operacje marszałkowskie w tle), ale przynajmniej robi to wszystko za kulisami.

niewytworność z Invoke

Wszyscy wiemy, że element UI można uzyskać tylko z wątku UI. Oznaczało to ogólnie, że programista musiał użyć operacji marszałkowskich poprzez ISynchronizeInvoke, DispatcherObject lub , aby przenieść kontrolę z powrotem do wątku interfejsu użytkownika. Ale spójrzmy prawdzie w oczy. Te operacje marshalingowe wyglądają brzydko. Task.ContinueWith uczyniło to nieco bardziej eleganckim, ale prawdziwa chwała przechodzi na await jako część nowego asynchronicznego modelu programowania C# 5. await można użyć do czekania, aż Task zostanie zakończone w taki sposób, że kontrola przepływu zostanie tymczasowo przerwana podczas wykonywania zadania, a następnie zwrócona w tym miejscu w odpowiednim kontekście synchronizacji. Nie ma nic bardziej eleganckiego i satysfakcjonującego niż użycie await jako zamiennika dla wszystkich tych połączeń Invoke.

programowanie równoległe

często widzę pytania pytając, jak rzeczy mogą się zdarzyć równolegle. Starym sposobem było stworzenie kilku wątków lub użycie ThreadPool. .NET 4.0 użył TPL i PLINQ. Klasa Parallel to świetny sposób na równoległe wykonywanie iteracji pętli. I PLINQ's AsParallel to inna strona tej samej monety dla zwykłego starego LINQ. Te nowe funkcje TPL znacznie upraszczają tę kategorię programowania wielowątkowego.

.NET 4.5 wprowadza bibliotekę Przepływ danych TPL. Ma to na celu stworzenie eleganckiego złożonego problemu programowania równoległego. Abstrahuje klasy do bloków. Mogą to być bloki docelowe lub bloki źródłowe. Dane mogą płynąć z jednego bloku do drugiego. Istnieje wiele różnych bloków, w tym BufferBlock<T>, BroadcastBlock<T>, ActionBlock<T> itd., Które wszystkie robią różne rzeczy. I oczywiście cała biblioteka zostanie zoptymalizowana do użycia z nowymi słowami kluczowymi async i await. Jest to ekscytujący nowy zestaw zajęć, który moim zdaniem będzie się powoli przyzwyczajał.

zakończenie Płynnego

jak masz wątku, aby zatrzymać? Często widzę to pytanie. Najprostszym sposobem jest zadzwonić pod numer Thread.Abort, ale wszyscy wiemy, jak to zrobić ... Mam nadzieję. Istnieje wiele różnych sposobów, aby to zrobić bezpiecznie. .NET 4.0 wprowadził bardziej zunifikowaną koncepcję zwaną anulowaniem za pośrednictwem CancellationToken i CancellationTokenSource. Zadania w tle mogą sondować IsCancellationRequested lub po prostu dzwonić pod ThrowIfCancellationRequested w bezpiecznych punktach, aby z wdzięcznością przerwać pracę, którą wykonali. Inne wątki mogą zadzwonić pod numer Cancel, aby poprosić o anulowanie.

+0

Wow, to jest to, czego potrzebowałem! Szukałem wszystkiego, żeby zobaczyć rzeczy o tysiąc stóp i to jest to. Szkoda, że ​​ludzie zamknęli to pytanie; Nominowałem go do ponownego otwarcia. – LamonteCristo

+0

Czy rozszerzenia reaktywne (Rx) i StreamInsight również powinny znajdować się na tej liście? – LamonteCristo

+0

@ makerofthings7: Prawdopodobnie ... kiedy dostanę czas, zrobię to. –

1

Task i Task<T>, ale oni byli tu od .NET 4. async niekoniecznie pracować z wątków, zobacz Jon's video from Øredev za bardzo dobre wyjaśnienie.

2

Bez wątpienia zapoznanie się z nową biblioteką Tpl DataFlow (zawartą w .net 4.5) da ci największy impuls pod względem równoczesnego rozwoju.

Jeśli poważnie myślisz o bardzo równoczesnych aplikacjach, spędź dzień lub dwa, zapoznając się z DataFlow. Jest naprawdę dobry.

7

Więc zobaczmy tutaj:

  1. Klasa ThreadPool - trochę stary, ale wciąż niezawodny prostego wzoru producent-konsumentów.
  2. BackgoundWorker (.NET 2.0+) - kolejna staroświecka konstrukcja, zapewniająca przydatne funkcje do wykonywania zadań w tle w aplikacjach GUI.
  3. Timer s - przydatne do wykonywania kodu w określonych odstępach czasu z użyciem wątku tła.
  4. Klasa Task (.NET 4.0+) - wątkowanie abstrakcji, które działają na podstawowej puli wątków i zapewnia wiele przydatnych funkcji, takich jak tworzenie wyjątków i planowanie. Przydatny do tak zwanego "równoległego zadania".
  5. Parallel.For, Parallel.ForEach (.NET 4.0+) - dobry do wykonywania tej samej operacji na zbiorze danych równolegle. Przydatny w przypadku tak zwanego "paralelizmu danych".
  6. Parallel.Invoke (.NET 4.0+) - dalsza abstrakcja nad Task s. Po prostu odpala kilka kawałków kodu (metod, lambdas) równolegle.
  7. Równoczesne kolekcje (.NET 4.0+) - wszystko, czego potrzebujesz, aby przekazywać lub współdzielić dane między wątkami w wydajny i bezpieczny sposób.
Powiązane problemy