Jaka jest różnica między zadaniem a wątkiem?

378

W języku C # 4.0, mamy Taskw System.Threading.Tasks nazw. Jaka jest prawdziwa różnica między Threadi Task. Zrobiłem jakiś przykładowy program (pomoc wzięta z MSDN) dla własnego uczenia się

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 

ale mają wiele wątpliwości, ponieważ pomysł nie jest tak jasny.

Początkowo szukałem w Stackoverflow podobnego typu pytania, ale być może z tym tytułem pytania nie byłem w stanie uzyskać tego samego. Jeśli ktoś wie o tym samym typie pytania zamieszczonego tutaj wcześniej, uprzejmie podaj odnośnik do linku.

hippietrail
źródło
8
wątki wykonują zadania
pm100,

Odpowiedzi:

314

Zadanie to coś, co chcesz zrobić.

Wątek jest jednym z wielu możliwych pracowników wykonujących to zadanie.

W terminologii .NET 4.0 zadanie reprezentuje operację asynchroniczną. Wątki służą do zakończenia tej operacji poprzez podzielenie pracy na części i przypisanie do osobnych wątków.

Mitch Pszenica
źródło
Czy możesz podać podstawowy przykład wątków, które wykonują zadanie? Nie wiem, czy wątki wykonują prace, które są od siebie niezależne, czy też wykonują jakieś obliczenia pracy zespołowej ?
pensum
Oba scenariusze są możliwe: w optymalnej sytuacji wątki wykonują niezależną pracę bez potrzeby synchronizacji z innymi wątkami. W praktyce zamki służą do koordynowania wątków.
Mitch Wheat
451

Z punktu widzenia informatyki a Taskjest przyszłością lub obietnicą . (Niektórzy ludzie używają tych dwóch terminów synchronicznie, inni używają ich inaczej, nikt nie może zgodzić się na dokładną definicję.) Zasadniczo Task<T>„obietnica” zwróci ci T, ale nie teraz kochanie, jestem trochę zajęta, dlaczego nie wrócisz później?

To Threadsposób na spełnienie tej obietnicy. Ale nie każdy Taskpotrzebuje zupełnie nowego Thread. (W rzeczywistości tworzenie wątku jest często niepożądane, ponieważ jest to znacznie droższe niż ponowne użycie istniejącego wątku z puli wątków. Więcej na ten temat za chwilę.) Jeśli wartość, na którą czekasz, pochodzi z systemu plików lub bazy danych lub sieci, nie ma potrzeby, aby wątek siedział i czekał na dane, gdy może obsługiwać inne żądania. Zamiast tego Taskmoże zarejestrować wywołanie zwrotne, aby otrzymać wartości, gdy będą gotowe.

W szczególności, Taskczy nie powiedzieć, dlaczego jest to, że zajmuje tak dużo czasu, aby zwrócić wartość. To może być tak, że to zajmuje dużo czasu, aby obliczyć, czy to może, że to zajmuje dużo czasu, aby pobrać. Tylko w pierwszym przypadku użyłbyś a Threaddo uruchomienia Task. (W .NET wątki są cholernie drogie, więc na ogół chcesz ich unikać w jak największym stopniu i naprawdę używaj ich tylko wtedy, gdy chcesz uruchomić wiele ciężkich obliczeń na wielu procesorach. Na przykład w systemie Windows wątek waży 12 KiByte ( Myślę, że) w Linuksie wątek waży zaledwie 4 KiByte, w Erlang / BEAM nawet zaledwie 400 bajtów. W .NET to 1 MiByte!)

Jörg W Mittag
źródło
29
Co ciekawe we wczesnych wersjach zapoznawczych TPL (Task Parallel Library) pojawiło się Zadanie i przyszłość <T>. Nazwa Future <T> została następnie przemianowana na Task <T>. :)
Lee Campbell
23
Jak obliczyłeś 1 MB dla platformy .NET?
dvallejo,
5
@DanVallejo: Numer ten został wspomniany w wywiadzie dla zespołu projektowego TPL. Nie mogę ci powiedzieć, kto to powiedział ani jaki wywiad to obejrzałem lata temu.
Jörg W Mittag,
9
@RIPUNJAYTRIPATHI Jasne, ale nie musi to być kolejny wątek, może to być wątek, który w pierwszej kolejności zażądał pracy.
Chris Pitman
7
.NET używa po prostu wątków Windows w systemie Windows, więc rozmiar jest taki sam - domyślnie zwykle 1 MiB pamięci wirtualnej dla obu. Pamięć fizyczna jest używana w razie potrzeby w porcjach wielkości strony (zwykle 64 kiB), podobnie jak w przypadku kodu natywnego. Minimalny rozmiar stosu wątków zależy na przykład od OS - 256 kiB dla Visty. W systemie Linux x86 wartością domyślną jest zwykle 2 MiB - ponownie, podzielone na porcje wielkości strony. (uproszczenie) Erlang używa tylko jednego wątku systemowego na proces, te 400 bajtów odnosi się do czegoś podobnego do .NET Task.
Luaan,
39

Wątek

Goły metal, prawdopodobnie nie musisz go używać, prawdopodobnie możesz użyć LongRunningzadania i czerpać korzyści z TPL - Task Parallel Library, zawartej w .NET Framework 4 (luty 2002) i wyżej (także .NET Rdzeń).

Zadania

Abstrakcja nad wątkami. To korzysta z puli wątków (chyba, że zadanie określić jako LongRunningdziałania, jeśli tak, to nowy wątek jest tworzony pod maską dla Ciebie).

Pula wątków

Jak sama nazwa wskazuje: pula wątków. Czy środowisko .NET obsługuje dla Ciebie ograniczoną liczbę wątków? Dlaczego? Ponieważ otwarcie 100 wątków w celu wykonania kosztownych operacji procesora na procesorze z zaledwie 8 rdzeniami zdecydowanie nie jest dobrym pomysłem. Framework zachowa dla ciebie tę pulę, ponownie wykorzystując wątki (nie tworząc / nie zabijając ich przy każdej operacji) i wykonując niektóre z nich równolegle, w taki sposób, aby procesor się nie spalił.

OK, ale kiedy użyć każdego z nich?

Wznów: zawsze używaj zadań.

Zadanie jest abstrakcją, więc jest o wiele łatwiejsze w użyciu. Radzę zawsze starać się używać zadań, a jeśli napotkasz jakiś problem, który powoduje, że musisz samodzielnie poradzić sobie z wątkiem (prawdopodobnie 1% czasu), użyj wątków.

ALE pamiętaj, że:

  • Wiązanie we / wy : w przypadku operacji związanych z we / wy (wywołania bazy danych, pliki do odczytu / zapisu, wywołania interfejsów API itp.) Unikaj normalnych zadań, w razie potrzeby używaj LongRunningzadań ( lub wątków ). Ponieważ korzystanie z zadań doprowadziłoby cię do puli wątków z kilkoma zajętymi wątkami i wieloma kolejnymi zadaniami czekającymi na swoją kolej.
  • Wiązanie procesora : W przypadku operacji związanych z procesorem wystarczy korzystać z normalnych zadań (które wewnętrznie wykorzystają pulę wątków) i być szczęśliwym.
Fabriciorissetto
źródło
lekka korekta, Wątek nie jest „gołym metalem”. jest implementowany przez system operacyjny, większość implementacji opiera się na funkcjach CPU i CS, ale nie są one implementowane przez sprzęt.
Tomer W
7

Możesz użyć, Taskaby określić, co chcesz zrobić, a następnie dołączyć to Taskza pomocą Thread. więc Taskbyłoby to wykonane w tym nowo utworzonym, Threada nie w wątku GUI.

Użyj Taskz TaskFactory.StartNew(Action action). Tutaj wykonujesz delegata, więc jeśli nie użyjesz żadnego wątku, zostanie on wykonany w tym samym wątku (wątek GUI). Jeśli wspominasz o wątku, możesz to zrobić Taskw innym wątku. Jest to niepotrzebna praca, ponieważ możesz bezpośrednio wykonać delegata lub dołączyć go do wątku i wykonać go w tym wątku. Więc nie używaj tego. to po prostu niepotrzebne. Jeśli zamierzasz zoptymalizować swoje oprogramowanie, jest to dobry kandydat do usunięcia.

** Należy pamiętać, że Actionjest to delegate.

Grypy
źródło
6

Oprócz powyższych punktów dobrze byłoby wiedzieć, że:

  1. Zadanie jest domyślnie zadaniem w tle. Nie możesz mieć zadania na pierwszym planie. Z drugiej strony wątek może być tłem lub pierwszym planem (użyj właściwości IsBackground, aby zmienić zachowanie).
  2. Zadania utworzone w puli wątków przetwarzają wątki, co pomaga oszczędzać zasoby. Tak więc w większości przypadków zadania powinny być domyślnym wyborem.
  3. Jeśli operacje są szybkie, znacznie lepiej jest użyć zadania zamiast wątku. W przypadku długotrwałych operacji zadania nie mają przewagi nad wątkami.
użytkownik2492339
źródło
4

Zwykle używam Taskdo interakcji z Winforms i prostym mechanizmem pracującym w tle, aby nie zamrażał interfejsu użytkownika. tutaj przykład, kiedy wolę używaćTask

private async void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    await Task.Run(() => {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
    })
    buttonDownload.Enabled = true;
}

VS

private void buttonDownload_Click(object sender, EventArgs e)
{
    buttonDownload.Enabled = false;
    Thread t = new Thread(() =>
    {
        using (var client = new WebClient())
        {
            client.DownloadFile("http://example.com/file.mpeg", "file.mpeg");
        }
        this.Invoke((MethodInvoker)delegate()
        {
            buttonDownload.Enabled = true;
        });
    });
    t.IsBackground = true;
    t.Start();
}

Różnica polega na tym, że nie musisz używać MethodInvokerkrótszego kodu.

ewwink
źródło
4

Zadanie jest jak operacja, którą chcesz wykonać. Wątek pomaga zarządzać tą operacją przez wiele węzłów procesu. zadanie jest lekką opcją, ponieważ Threading może prowadzić do złożonego zarządzania kodem.
Sugeruję, aby zawsze czytać z MSDN (Best in world)

Zadanie

Wątek

Saurabh
źródło
3

Zadanie może być postrzegane jako wygodny i łatwy sposób wykonywania czegoś asynchronicznie i równolegle.

Normalnie zadanie jest wszystkim, czego potrzebujesz, nie pamiętam, czy kiedykolwiek użyłem wątku do czegoś innego niż eksperymentowanie.

Możesz osiągnąć to samo za pomocą wątku (z dużym wysiłkiem), jak w przypadku zadania.

Wątek

int result = 0;
Thread thread = new System.Threading.Thread(() => { 
    result = 1; 
});
thread.Start();
thread.Join();
Console.WriteLine(result); //is 1

Zadanie

int result = await Task.Run(() => {
    return 1; 
});
Console.WriteLine(result); //is 1

Zadanie domyślnie korzysta z Threadpool, który oszczędza zasoby, ponieważ tworzenie wątków może być kosztowne. Możesz zobaczyć Zadanie jako abstrakcję wyższego poziomu w wątkach.

Jak wskazuje ten artykuł , zadanie zapewnia następujące zaawansowane funkcje nad wątkiem.

  • Zadania są dostosowane do wykorzystywania procesorów wieloprocesorowych.

  • Jeśli system ma wiele zadań, korzysta wewnętrznie z puli wątków CLR, więc nie ma narzutu związanego z tworzeniem dedykowanego wątku za pomocą wątku. Skróć także czas przełączania kontekstu między wieloma wątkami.

  • Zadanie może zwrócić wynik. Nie ma bezpośredniego mechanizmu zwracającego wynik z wątku.
  • Poczekaj na zestaw zadań, bez konstrukcji sygnalizacyjnej.

  • Możemy łączyć ze sobą zadania, aby wykonywać je jedno po drugim.

  • Nawiąż relację rodzic / dziecko, gdy jedno zadanie zostanie uruchomione z innego zadania.

  • Wyjątek zadania podrzędnego można propagować do zadania nadrzędnego.

  • Obsługa zadań anulowania za pomocą tokenów anulowania.

  • Implementacja asynchroniczna jest łatwa w użyciu, dzięki słowom kluczowym „async” i „czekaj”.

CharithJ
źródło