Qual è la differenza tra attività e thread?

In C # 4.0, abbiamo Task nello spazio dei nomi System.Threading.Tasks . Qual è la vera differenza tra Thread e 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.

Ho inizialmente cercato in StackOverflow per un tipo simile di domanda, ma potrebbe essere con questo titolo di domanda che non ero in grado di ottenere lo stesso. Se qualcuno conosce lo stesso tipo di domanda che viene postata qui in precedenza, fornisci gentilmente il riferimento del link.

Un compito è qualcosa che vuoi fare.

Una discussione è uno dei tanti possibili lavoratori che svolge tale compito.

Nei termini di .NET 4.0, un’attività rappresenta un’operazione asincrona. Thread (s) vengono utilizzati per completare l’operazione suddividendo il lavoro in blocchi e assegnando a thread separati.

In termini di informatica, un Task è un futuro o una promise . (Alcune persone usano questi due termini sinonimo, alcuni li usano in modo diverso, nessuno può essere d’accordo su una definizione precisa .) Fondamentalmente, un Task “promette” di restituirti una T , ma non ora tesoro, sono un po ‘occupato , perché non torni più tardi?

Un Thread è un modo per soddisfare questa promise. Ma non tutte le Task bisogno di una Thread nuova di zecca. (In effetti, creare un thread è spesso indesiderabile, perché farlo è molto più costoso del riutilizzo di un thread esistente dal threadpool. Più su quello in un momento.) Se il valore che si sta aspettando proviene dal filesystem o da un database o la rete, quindi non è necessario che un thread si sieda e attenda i dati quando può servire altre richieste. Invece, l’ Task potrebbe registrare un callback per ricevere i valori quando sono pronti.

In particolare, l’ Task non dice perché è necessario tanto tempo per restituire il valore. Potrebbe essere che ci vuole molto tempo per calcolare, o potrebbe richiedere molto tempo per andare a prendere. Solo nel primo caso Thread una Thread per eseguire un’attività. (In .NET, i thread sono esageratamente costosi, quindi in genere si vuole evitarli il più ansible e in realtà li si usa solo se si desidera eseguire più pesanti calcoli su più CPU.Ad esempio, in Windows, un thread pesa 12 KiByte ( Penso che, in Linux, un thread pesa appena 4 KiByte, in Erlang / BEAM anche solo 400 byte. In .NET, è 1 MiByte!)

Quando eseguiamo le cose su più thread, non è garantito che i thread siano separati tra più processori.

Task è un object leggero per la gestione di un’unità di lavoro parallelizzabile. Può essere utilizzato ogni volta che si desidera eseguire qualcosa in parallelo. Parallelo significa che il lavoro è distribuito su più processori per massimizzare la velocità di calcolo. Le attività sono ottimizzate per sfruttare i processori multicore.

L’attività fornisce le seguenti potenti funzionalità sul thread.

  • Se il sistema ha più attività, utilizza internamente il pool di thread CLR e quindi non ha il sovraccarico associato alla creazione di un thread dedicato utilizzando il thread. Riduci anche il tempo di cambio di contesto tra più thread.
  • L’attività può restituire un risultato. Non esiste un meccanismo diretto per restituire il risultato dal thread.
  • Aspetta un insieme di compiti, senza un costrutto di segnalazione.

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

  • Stabilire una relazione genitore / figlio quando un’attività viene avviata da un’altra attività.

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

  • Cancellazione del supporto delle attività tramite l’utilizzo di token di cancellazione.

  • L’implementazione asincrona è facile nell’attività, utilizzando le parole chiave ‘asincrono’ e ‘aspetta’.

Filo

La cosa nuda del metallo, probabilmente non è necessario usarla, probabilmente è ansible utilizzare un’attività LongRunning e trarre i benefici dal TPL – Task Parallel Library, incluso in .NET Framework 4 (febbraio 2002) e superiore (anche. NET Core).

Compiti

Astrazione sopra i fili. Utilizza il pool di thread (a meno che non si specifichi l’operazione come operazione LongRunning , in tal caso, viene creato un nuovo thread sotto il cofano per te).

Pool di thread

Come suggerisce il nome: un pool di fili. Il framework .NET gestisce un numero limitato di thread per te. Perché? Perché aprire 100 thread per eseguire costose operazioni CPU su un processore con soli 8 core non è sicuramente una buona idea. Il framework manterrà questo pool per te, riutilizzando i thread (non creando / uccidendoli ad ogni operazione) ed eseguendo alcuni di essi in parallelo, in modo che la tua CPU non brucerà.

OK, ma quando usarli?

In curriculum: usa sempre le attività.

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

MA sii consapevole che:

  • Limite I / O : per operazioni con I / O (chiamate database, file di lettura / scrittura, chiamate API, ecc.) Evitare l’uso di attività normali, utilizzare attività LongRunning ( o thread se necessario ). Perché l’utilizzo delle attività porterebbe a un pool di thread con alcuni thread occupati e molte altre attività che attendono il turno per prendere il pool.
  • Limite della CPU : per le operazioni associate alla CPU basta utilizzare le normali attività (che internamente utilizzerà il pool di thread) e sii felice.

Puoi usare Task per specificare cosa vuoi fare, quindi albind Task con una Thread . in modo che Task venga eseguita in Thread appena creato anziché nel thread GUI.

Utilizzare Task con TaskFactory.StartNew(Action action) . Qui esegui un delegato, quindi se non utilizzi alcun thread verrebbe eseguito nello stesso thread (thread della GUI). Se si menziona una discussione è ansible eseguire questa Task in una discussione diversa. Questo è un lavoro non necessario perché è ansible eseguire direttamente il delegato o albind 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.

** Si prega di notare che l’ Action è un delegate .

Oltre ai punti di cui sopra, 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 (usa la proprietà IsBackground per cambiare il comportamento).
  2. Le attività create nel pool di thread riciclano i thread che consentono di risparmiare risorse. Quindi nella maggior parte dei casi le attività dovrebbero essere la scelta predefinita.
  3. Se le operazioni sono veloci, è molto meglio utilizzare un’attività anziché il thread. Per le operazioni a esecuzione prolungata, le attività non offrono molti vantaggi rispetto ai thread.

L’attività è come un’operazione che si desidera eseguire, Thread aiuta a gestire tali operazioni attraverso più nodes di processo. task è un’opzione leggera poiché Threading può portare a una gestione complessa del codice
Suggerirò di leggere sempre da MSDN (Best in world)

Compito

Filo

Di solito uso Task per interagire con Winforms e un semplice background worker per non congelare l’interfaccia utente. qui un esempio quando preferisco usare 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() { btnDownloadAccelerator.Enabled = true; }); }); t.IsBackground = true; t.Start(); } 

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