2012-04-26 7 views
28

In C# v'è alcuna differenza tra l'utilizzo di un delegato per fare qualche lavoro in modo asincrono (chiamata BeginInvoke()) e con una filettatura ThreadPool come mostrato sottoDifferenza tra delegate.BeginInvoke e utilizzando fili ThreadPool in C#

public void asynchronousWork(object num) 
    { 
     //asynchronous work to be done 
     Console.WriteLine(num); 
    } 

public void test() 
    { 
     Action<object> myCustomDelegate = this.asynchronousWork; 
     int x = 7; 

     //Using Delegate 
     myCustomDelegate.BeginInvoke(7, null, null); 

     //Using Threadpool 
     ThreadPool.QueueUserWorkItem(new WaitCallback(asynchronousWork), 7); 
     Thread.Sleep(2000); 
    } 

Modifica:
BeginInvoke si assicura che un thread dal pool di thread venga utilizzato per eseguire il codice asincrono, quindi c'è qualche differenza?

+1

possibile duplicato del [fa Funz .BeginInvoke utilizzare il ThreadPool?] (Http://stackoverflow.com/questions/3556634/does-funct-begininvoke-use-the-threadpool) – nothrow

+0

Non sono sicuro se il tuo commento era prima che ho modificato la mia domanda, ma sono consapevole che BeginInvoke esegue delegati sui thread che appartengono al threadpool. La mia domanda era più se ci fosse qualche differenza tra l'esecuzione esplicita del metodo su un pool di thread utilizzando QueueUserWorkItem o usando BeginInvoke – nighthawk457

risposta

31

Joe Duffy, nel suo libro Concurrent Programming on Windows (pagina 418), dice questo circa Delegate.BeginInvoke:

Tutti i tipi di delegati, per offerta convenzione un BeginInvoke e EndInvoke metodo accanto al normale metodo di sincrono Invoke. Sebbene si tratti di una buona funzionalità del modello di programmazione, dovresti stare lontano da loro ovunque sia possibile. L'implementazione utilizza un'infrastruttura remota che impone un overhead considerevole alla chiamata asincrona. Il lavoro in coda per il pool di thread direttamente è spesso un approccio migliore, anche se ciò significa che devi coordinare te stesso la logica del rendez-vous.

EDIT: Ho creato la seguente semplice test delle relative spese generali:

int counter = 0; 
int iterations = 1000000; 
Action d =() => { Interlocked.Increment(ref counter); }; 

var stopwatch = new System.Diagnostics.Stopwatch(); 
stopwatch.Start(); 
for (int i = 0; i < iterations; i++) 
{ 
    var asyncResult = d.BeginInvoke(null, null); 
} 

do { } while(counter < iterations); 
stopwatch.Stop(); 

Console.WriteLine("Took {0}ms", stopwatch.ElapsedMilliseconds); 
Console.ReadLine(); 

Sulla mia macchina le corse di prova di cui sopra in circa 20 secondi. Sostituzione della chiamata BeginInvoke con

System.Threading.ThreadPool.QueueUserWorkItem(state => 
{ 
    Interlocked.Increment(ref counter); 
}); 

cambia il tempo di esecuzione di 864ms.

+1

Mi sento un'altra reazione istintiva? Abbiamo bisogno di alcuni dati empirici per oggettivare * un overhead considerevole per l'invocazione asincrona. * Qual è il compromesso necessario per * coordinare te stesso la logica del rendez-vous ... * rispetto allo zucchero sintattico delle implementazioni asincrone generalmente accettate - ad es. BeginInvoke, Callback, EndInvoke. Una cosa che usiamo di IAsyncResult è una maniglia da cui possiamo monitorare cosa sta succedendo. Non ho mai provato nulla usando il ThreadPool per vedere se potevo fare lo stesso. – IAbstract

+1

Mi chiedo perché ciascun delegato definisce un metodo 'BeginInvoke' che avvia il delegato in modo asincrono? L'unico aspetto di "BeginInvoke" che sembra legato a una particolare firma delegata sarebbe il processo di conversione di un delegato più parametri in un elemento unificato, che avrebbe potuto essere eseguito altrettanto bene se ogni delegato avesse definito il metodo "Bind" che stessi parametri del delegato e ha restituito un 'MethodInvoker'. – supercat

+1

@IAbstract - Si tratta in particolare di 'Delegate.Begin \ EndInvoke' non del modello generale' BeginInvoke \ EndInvoke' trovato nel framework. È vero che 'IAsyncResult' ti dà più controllo, tuttavia viene abbandonato a favore di' Task' in .net 4 e versioni successive. – Lee