2013-07-02 9 views
31

Supponiamo di disporre di un metodo di I/O (come un metodo per effettuare chiamate DB). Questo metodo può essere eseguito sia in modo sincrono che asincrono. Cioè,Task.Factory.StartNew vs Task.Factory.FromAsync

  1. Sync:

    IOMethod() 
    
  2. asincrono:

    BeginIOMethod() 
    EndIOMethod() 
    

Poi quando eseguiamo il metodo in diversi modi, come mostrato sotto, qual è la differenza di prestazioni in termini dell'utilizzo delle risorse?

  1. var task = Task.Factory.StartNew(() => { IOMethod(); }); 
    task.Wait(); 
    
  2. var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ...); 
    task.Wait(); 
    
+2

La risposta breve, non è (probabilmente) che non ci sia un thread thread in cui non si fa nulla quando si utilizza 'FromAsync', lo si è se si utilizza' StartNew'. Se stai facendo un sacco di cose, sottolineare il pool di thread potrebbe essere un problema di prestazioni. – Servy

+0

Duplicato: http://stackoverflow.com/questions/5018897/tpl-taskfactory-fromasync-vs-tasks-with-blocking-methods – shambulator

risposta

53
var task = Task.Factory.StartNew(() => { IOMethod(); }); 
task.Wait(); 

Questo bloccherà un filo pool di thread mentre IOMethod() è l'esecuzione e anche bloccare il tuo thread corrente a causa del Wait(). Totale thread bloccati: 2.

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ...); 
task.Wait(); 

Questa volontà (più probabile) eseguire l'operazione in modo asincrono senza utilizzare un filo, ma bloccherà il thread corrente a causa della Wait(). Totale discussioni bloccate: 1.

IOMethod(); 

Questo bloccherà il thread corrente mentre IOMethod() è in esecuzione. Totale thread bloccati: 1.

Se è necessario bloccare il thread corrente, o se il blocco è ok per te, allora dovresti usare questo, perché provare ad usare TPL non ti darà nulla.

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ...); 
await task; 

Questo sarà eseguire l'operazione in modo asincrono senza utilizzare un filo, e sarà anche attendere il completamento dell'operazione asincrono, grazie alla await. Totale thread bloccati: 0.

Questo è ciò che si dovrebbe usare se si desidera sfruttare l'asincronia e si può usare C# 5.0.

var task = Task.Factory.FromAsync(BeginIOMethod, EndIOMethod, ...); 
task.ContinueWith(() => /* rest of the method here */); 

Questo sarà eseguire l'operazione in modo asincrono senza utilizzare un filo, e sarà anche attendere il completamento dell'operazione asincrono, grazie alla ContinueWith(). Totale thread bloccati: 0.

Questo è ciò che si dovrebbe usare se si desidera sfruttare l'asincronia e non è possibile utilizzare C# 5.0.

+2

Penso che "task.Wait()" sia stato introdotto solo per esempio. Sono certo che quando l'attività è in esecuzione, l'OP intende fare qualcosa in più lungo la strada. Quindi non penso che dovresti considerare il thread chiamante come un thread bloccato. Ma se era serio nell'attesa, allora hai ragione. – Tombala

+0

@Tombala Non vedo nulla nella domanda che lo indichi. Ma è certamente una possibilità. – svick

1

(1) sarà (probabilmente) causare il pool di thread .NET per elaborare la vostra Task.

(2) utilizzerà qualsiasi meccanismo utilizzato dalla coppia BeginIOMethod/EndIOMethod in modo nativo per gestire la parte asincrona, che potrebbe o meno coinvolgere il pool di thread .NET.

Ad esempio, se il BeginIOMethod sta inviando un messaggio TCP attraverso la rete internet, e in un secondo momento il destinatario sta per inviare un messaggio TCP in risposta (ricevuto da EndIOMethod), allora la natura asincrona dell'operazione è non viene fornito dal pool di thread .NET. La libreria TCP in uso sta fornendo la parte asincrona.

Questa operazione può essere eseguita utilizzando TaskCompletionSource class. Task.Factory.FromAsync, è possibile creare un Task<T>, restituire il Task<T>, quindi utilizzare EndIOMethod come trigger per inserire Result nello Task<T> restituito dal modulo Task.Factory.FromAsync al momento della chiamata.

Qual è la differenza di prestazioni in termini di utilizzo delle risorse?

La differenza tra (1) e (2) è principalmente se il pool di thread .NET avrà o meno il suo carico di lavoro aggiunto. In generale, la cosa giusta da fare è scegliere Task.Factory.FromAsync se si dispone solo di una coppia Begin.../End... e Task.Factory.StartNew.


Se stai usando C# 5.0, allora si dovrebbe utilizzare il non-blocking await task; invece di task.Wait();. (Si veda la risposta del svick.)

+0

Non è (ancora) necessario avviare una discussione per eseguire BeginIOMethod? Non sarebbe ancora una discussione nel pool di thread? Secondo [questa domanda] (http://stackoverflow.com/questions/7784589/how-does-task-factory-fromasync-work-behave), FromAsync utilizza anche il pool di thread. – Tombala

+0

@Tombala Il 'BeginIOMethod' viene eseguito in modo completamente sincrono sul thread che chiama' FromAsync'. --- Sulla risposta a questa domanda, vedere questo commento: "L'attività risultante verrà, per impostazione predefinita, eseguita su un thread pool di thread" - solo se l'operazione richiede effettivamente un thread da eseguire. Ad esempio, le operazioni di I/O useranno una porta di completamento I/O piuttosto che una discussione. Questo si adatta meglio in quanto i thread sono una risorsa limitata e alquanto costosa. –

+0

Corretto ma il resto della conversazione indica anche la possibilità che tali callback si verifichino su un thread del thread. Quindi, a seconda dell'implementazione di come Begin e End viene eseguito, l'utilizzo potrebbe essere lo stesso, meno o anche di più. Per esempio. se Begin e End avviano i thread per eseguire la loro operazione asincrona anziché i callback delle porte, è possibile che anch'essi possano aggiungere al pool di thread. – Tombala

Problemi correlati