2011-11-28 6 views
18

Zaktualizowałem swój kod, aby używać zadań zamiast wątków ...Czy powinienem zauważyć różnicę w używaniu zadania vs wątków w .Net 4.0?

Patrząc na użycie pamięci i procesor, nie widzę żadnych ulepszeń na wielordzeniowym komputerze, czy jest to oczekiwane?

Moja aplikacja uruchamia się zasadniczo wątków/zadań w różnych obiektach, gdy pracuje on ...

Wszystko robię to prosta

Task a = new Task(...) 
a.Start(); 
+4

"Nie zauważam żadnych ulepszeń" To by tak bardzo zależało od rzeczywistego kodu ... Mogłeś nawet zauważyć pogorszenie. –

+1

'Zadania' nie są klasami magicznymi. W końcu są one również "wątkami", –

+0

Po prostu jednak Zadania są świadome środowiska wielordzeniowego, w przeciwieństwie do wątków, więc wiedzieliby, jak poprawnie się rozprowadzać na wielu rdzeniach. Również dlatego, że nie muszą być tworzone, ponieważ używają ThreadPool, będą bardziej wydajne pamięci. – TheWommies

Odpowiedz

28

Istnieją różne implikacje do korzystania Zadania zamiast wątków , ale wydajność nie jest znacząca (zakładając, że nie tworzysz ogromnej liczby wątków). Kilka kluczowych różnic:

  1. Domyślny TaskScheduler użyje łączenia wątków, więc niektóre Ta sks może się nie rozpocząć, dopóki nie zakończą się inne oczekujące Zadania. Jeśli użyjesz wątku bezpośrednio, każde użycie spowoduje uruchomienie nowego wątku.
  2. Po wystąpieniu wyjątku w zadaniu, zostaje on zapakowany w wyjątek AggregateException, że kod wywołujący może zostać odebrany, gdy oczekuje na zakończenie zadania lub jeśli rejestruje kontynuację zadania. Dzieje się tak dlatego, że możesz wykonywać takie czynności, jak oczekiwanie na wiele zadań, w którym to przypadku można zgłaszać i agregować wiele wyjątków.
  3. Jeśli nie zauważysz nieobsługiwanego wyjątku wygenerowanego przez zadanie, to (dobrze, może) zostanie ostatecznie wyrzucony przez finalizatora zadania, co jest szczególnie nieprzyjemne. Zawsze polecam zahaczenie zdarzenia TaskScheduler.UnobservedTaskException, abyś mógł przynajmniej zarejestrować te błędy, zanim aplikacja rozwali się. Różni się to od wyjątków Thread, które pojawiają się w zdarzeniu AppDomain.UnhandledException.
+0

Bardzo pomocne podsumowanie, dziękuję! –

+0

Dzięki, to niezły przegląd. Teraz szukam pierwszego punktu, interesujące jest użycie TaskScheduler. – Kosko

+1

@Kosko, jednym z typowych zastosowań TaskScheduler jest [TaskScheduler.FromCurrentSynchronizationContext] (http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskscheduler.fromcurrentsynchronizationcontext.aspx), który planuje zadania do kontekst synchronizacji (zazwyczaj wątek interfejsu użytkownika). Jest to najczęściej używane podczas rejestrowania kontynuacji zadania, aby kontynuacja działała w wątku interfejsu użytkownika, a nie w puli wątków. Pomoże to uniknąć wielu brzydkich kodów Invoke w twoich metodach aktualizacji interfejsu użytkownika. –

3

Jednym ze znaczących ulepszeń Takss vs. Threads jest łatwość tworzenia łańcuchów zadań. Można określić, kiedy zadanie ma się rozpocząć po poprzednim zadaniu ("OnSuccess", "OnError", a.s.o.) i można określić, czy powinien istnieć przełącznik kontekstu synchronizacji. Daje to świetną okazję do uruchomienia długiego zadania w bakcground, a następnie interfejsu użytkownika, który wykonuje zadanie w wątku interfejsu użytkownika.

8

Jeśli po prostu wymieniłeś każde użycie Thread na Task i nie zrobiłeś żadnych innych zmian, spodziewałbym się praktycznie takiej samej wydajności. Interfejs API Task jest tak naprawdę właśnie taki, to API na istniejącym zestawie konstruktów. Pod maską wykorzystuje wątki, aby zaplanować działania i dlatego ma podobne cechy wydajności.

Co to wielki temat Task są nowe rzeczy można zrobić z nimi

  • Kompozycja z ContinueWith
  • Rezygnacja
  • hierarchie
  • Etc ...
+2

TPL pozbywa się kodu obfuskującego wzdęcia. Jest to API, które każdy programista chce napisać, ale nie ma na to czasu. – Gusdor

0

Jeżeli jesteś używając .Net 4.0, możesz użyć równoległego.Wywołać metodę jak tak

Parallel.Invoke(()=> { 
    // What ever code you add here will get threaded. 
}); 

o więcej informacji patrz http://msdn.microsoft.com/en-us/library/dd992634.aspx

+1

Co takiego? Czytałeś pytanie? 'Patrząc na użycie pamięci i procesora, nie dostrzegam żadnych ulepszeń na wielordzeniowym PC, czy jest to oczekiwane?' –

+0

Rozumiem, że Parallel.Invoke ma lepsze wykorzystanie wielordzeniowych. Teraz mogę się mylić, jeśli tak, proszę mnie pouczyć. –

+0

1) Może, 'Parallel.Invoke' jest zaimplementowany z' Tasks'? 2) Gdzie jest odpowiedź na pytanie "Czy to jest oczekiwane?" –

0

Można by zobaczyć różnicę, jeśli oryginał lub przekształcone kod NIE utlize CPU całkowicie. To znaczy. jeżeli oryginalny kod zawsze ogranicza liczbę wątków do 2, na czterordzeniowym komputerze będzie działać z obciążeniem około 50% z ręcznie utworzonymi wątkami i potencjalnie z obciążeniem 100% z zadaniami (jeśli twoje zadania mogą być aktywowane paralellizująco). Wygląda więc na to, że albo oryginalny kod był rozsądny z punktu widzenia wydajności, albo obie implementacje cierpią na problemy z podobnym niewykorzystaniem CPU.