Qual è la differenza tra task e thread?


378

In C # 4.0, abbiamo Tasknello spazio dei nomi System.Threading.Tasks . Qual è la vera differenza tra Threade Task. Ho fatto un programma di esempio (aiuto preso da MSDN) per il mio bene di imparare con

Parallel.Invoke 
Parallel.For 
Parallel.ForEach 

ma ho molti dubbi in quanto l'idea non è così chiara.

Inizialmente ho cercato in StackOverflow un tipo di domanda simile ma potrei essere con questo titolo della domanda che non sono riuscito a ottenere lo stesso. Se qualcuno è a conoscenza dello stesso tipo di domanda pubblicata qui prima, si prega gentilmente di fornire il riferimento del collegamento.


8
i thread eseguono attività
pm100

Risposte:


315

Un'attività è qualcosa che vuoi fare.

Un thread è uno dei tanti possibili lavoratori che esegue tale compito.

NET 4.0 termini, un task rappresenta un'operazione asincrona. I thread vengono utilizzati per completare tale operazione suddividendo il lavoro in blocchi e assegnando thread separati.


Potresti fornire un esempio rudimentale di thread che funzionano per completare un'attività? Non so se i thread stanno facendo un lavoro indipendente tra loro o fanno dei calcoli sul lavoro di squadra ?
pensum

Entrambi gli scenari sono possibili: in una situazione ottimale, i thread svolgono un lavoro indipendente senza la necessità di sincronizzarsi con altri thread. In pratica, i blocchi vengono utilizzati per coordinare i thread.
Mitch Wheat,

451

In termini di informatica, a Taskè un futuro o una promessa . (Alcune persone usano questi due termini in modo sinonimo, altri li usano in modo diverso, nessuno può essere d'accordo su una definizione precisa .) Fondamentalmente, una Task<T>"promessa" di restituirti un T, ma non ora tesoro, sono un po 'impegnato, perché non torni più tardi?

A Threadè un modo per mantenere quella promessa. Ma non tutti hanno Taskbisogno di un nuovissimo Thread. (In effetti, la creazione di un thread è spesso indesiderabile, perché farlo è molto più costoso rispetto al riutilizzo di un thread esistente dal threadpool. Ne parleremo più avanti in un momento.) Se il valore che stai aspettando viene dal filesystem o da un database o rete, quindi non è necessario che un thread sieda e attenda i dati quando può servire altre richieste. Invece, Taskpotrebbe registrare un callback per ricevere i valori quando sono pronti.

In particolare, la Taskfa non dice perché è che ci vuole molto tempo per restituire il valore. Si potrebbe essere che ci vuole molto tempo per calcolare, o potrebbe che ci vuole molto tempo per andare a prendere. Solo nel primo caso useresti a Threadper eseguire a Task. (In .NET, i thread sono estremamente costosi, quindi in genere si desidera evitarli il più possibile e utilizzarli davvero solo se si desidera eseguire più calcoli pesanti su più CPU. Ad esempio, in Windows, un thread pesa 12 KiByte ( Penso), in Linux, un thread pesa appena 4 KiByte, in Erlang / BEAM anche solo 400 byte. In .NET, è 1 MiByte!)


29
È interessante notare che nelle prime versioni di anteprima di TPL (Task Parallel Library) c'era Task and Future <T>. Il futuro <T> è stato quindi rinominato nell'attività <T>. :)
Lee Campbell,

23
Come hai calcolato 1 MB per .NET?
dvallejo,

5
@DanVallejo: quel numero è stato menzionato in un'intervista con il team di progettazione di TPL. Non posso dirti chi l'ha detto o quale intervista è stata, l'ho vista anni fa.
Jörg W Mittag,

9
@RIPUNJAYTRIPATHI Certo, ma non è necessario che sia un altro thread, potrebbe essere il thread che ha richiesto il lavoro in primo luogo.
Chris Pitman,

7
.NET utilizza solo i thread di Windows su Windows, quindi le dimensioni sono le stesse: per impostazione predefinita, di solito 1 MiB di memoria virtuale per entrambi. La memoria fisica viene utilizzata secondo necessità in blocchi di dimensioni di pagina (di solito 64 kiB), lo stesso con il codice nativo. La dimensione minima dello stack di thread dipende dal sistema operativo, ad esempio 256 kiB per Vista. Su x86 Linux, il valore predefinito è di solito 2 MiB - di nuovo, allocato in blocchi di dimensioni pagina. (semplificazione) Erlang utilizza solo un thread di sistema per processo, quei 400 byte si riferiscono a qualcosa di simile a .NETs Task.
Luaan,

39

Filo

La cosa in metallo nudo, probabilmente non è necessario usarla, probabilmente è possibile utilizzare LongRunningun'attività e sfruttare i vantaggi della TPL - Task Parallel Library, inclusa in .NET Framework 4 (febbraio 2002) e versioni successive (anche .NET Nucleo).

Compiti

Astrazione sopra le discussioni. Esso utilizza il pool di thread (a meno che non si specifica il compito di LongRunningoperazione, in caso affermativo, un nuovo thread si crea sotto il cofano per voi).

Pool di thread

Come suggerisce il nome: un pool di thread. Il framework .NET gestisce un numero limitato di thread per te. Perché? Perché l'apertura di 100 thread per eseguire costose operazioni della CPU su un processore con solo 8 core non è sicuramente una buona idea. Il framework manterrà questo pool per te, riutilizzando i thread (non creando / uccidendoli ad ogni operazione) ed eseguendone alcuni in parallelo, in modo che la CPU non si bruci.

OK, ma quando usarli?

In ripresa: usa sempre le attività.

Il compito è un'astrazione, quindi è molto più facile da usare. Ti consiglio di provare sempre a usare le attività e se incontri qualche problema che ti rende necessario gestire un thread da solo (probabilmente l'1% delle volte), usa i thread.

MA tieni presente che:

  • Vincolo I / O : per le operazioni associate I / O (chiamate al database, file di lettura / scrittura, chiamate API, ecc.) Evitare di utilizzare le normali attività, utilizzare le LongRunningattività ( o i thread se necessario ). Perché l'uso delle attività porterebbe a un pool di thread con alcuni thread occupati e molte altre attività in attesa del suo turno per prendere il pool.
  • CPU Bound : per le operazioni legate alla CPU basta usare le normali attività (che internamente useranno il pool di thread) ed essere felici.

leggera correzione, una discussione non è una "cosa nuda". è implementato dal sistema operativo, la maggior parte delle implementazioni trasmette funzionalità della CPU e CS, ma non sono implementate dall'hardware.
Tomer W

7

È possibile utilizzare Taskper specificare ciò che si desidera fare, quindi allegarlo Taskcon a Thread. in modo che Taskvenga eseguito in quello appena creato Threadpiuttosto che sul thread della GUI.

Utilizzare Taskcon il TaskFactory.StartNew(Action action). Qui esegui un delegato, quindi se non utilizzassi alcun thread verrebbe eseguito nello stesso thread (thread GUI). Se si menziona un thread, è possibile eseguirlo Taskin un thread diverso. Questo è un lavoro non necessario perché è possibile eseguire direttamente il delegato o collegare quel delegato a un thread ed eseguire quel delegato in quel thread. Quindi non usarlo. è solo inutile. Se intendi ottimizzare il tuo software, questo è un buon candidato da rimuovere.

** Nota che Actionè a delegate.


6

Oltre ai punti precedenti, sarebbe bene sapere che:

  1. Un'attività è per impostazione predefinita un'attività in background. Non puoi avere un'attività in primo piano. D'altra parte un thread può essere in background o in primo piano (utilizzare la proprietà IsBackground per modificare il comportamento).
  2. Le attività create nel pool di thread riciclano i thread, consentendo di risparmiare risorse. Quindi nella maggior parte dei casi le attività dovrebbero essere la scelta predefinita.
  3. Se le operazioni sono rapide, è molto meglio utilizzare un'attività anziché il thread. Per operazioni di lunga durata, le attività non offrono molti vantaggi rispetto ai thread.

4

Di solito uso Taskper interagire con Winforms e il semplice background worker per evitare che blocchi l'interfaccia utente. qui un esempio quando preferisco usareTask

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();
}

la differenza è che non è necessario utilizzare MethodInvokerun codice più breve.


4

L'attività è come un'operazione che si desidera eseguire, Thread aiuta a gestire tale operazione attraverso più nodi di processo. compito è un'opzione leggero come Threading può portare a una gestione del codice complesso
vi suggerisco di leggere da MSDN (Best in mondo) sempre

Task

Filo


3

Un'attività può essere vista come un modo comodo e semplice per eseguire qualcosa in modo asincrono e in parallelo.

Normalmente un compito è tutto ciò che serve, non ricordo se ho mai usato un thread per qualcos'altro che la sperimentazione.

Puoi ottenere lo stesso risultato con un thread (con un grande sforzo) come puoi con un'attività.

Filo

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

Compito

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

Per impostazione predefinita, un'attività utilizzerà il pool di thread, che consente di risparmiare risorse poiché la creazione di thread può essere costosa. Puoi vedere un'attività come un'astrazione di livello superiore sui thread.

Come sottolineato in questo articolo , l'attività fornisce le seguenti potenti funzionalità oltre il thread.

  • Le attività sono ottimizzate per sfruttare i processori multicore.

  • Se il sistema ha più attività, utilizza internamente il pool di thread CLR e quindi non ha l'overhead associato alla creazione di un thread dedicato utilizzando il thread. Riduci anche il tempo di commutazione del contesto tra più thread.

  • L'attività può restituire un risultato. Non esiste alcun meccanismo diretto per restituire il risultato dal thread.
  • Attendere una serie di attività, senza un costrutto di segnalazione.

  • Possiamo concatenare le attività per eseguirle una dopo l'altra.

  • Stabilire una relazione padre / figlio quando un'attività viene avviata da un'altra attività.

  • L'eccezione dell'attività figlio può propagarsi all'attività padre.

  • Annullamento del supporto attività tramite l'utilizzo di token di annullamento.

  • L'implementazione asincrona è semplice, grazie alle parole chiave "asincrono" e "attende".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.