2012-10-29 11 views
24

Windows 7, Intel Core i3, a 64 bit, RAM da 4 GB, 2,27 GHz
.NET Framework 4.0
Perché tanta differenza di prestazioni tra Thread e Task?

Ho il seguente codice:

static void Main(string[] args) 
{ 
    var timer = new Stopwatch(); 
    timer.Start(); 

    for (int i = 0; i < 0xFFF; ++i) 
    { 
     // I use one of the following line at time 
     Task.Factory.StartNew(() => { }); 
     new Thread(() => { }).Start(); 
    } 

    timer.Stop(); 

    Console.WriteLine(timer.Elapsed.TotalSeconds); 
    Console.ReadLine(); 
} 

Se uso Task l'uscita è sempre meno di 0,01 secondi, ma se utilizzo Thread l'output è sempre maggiore di 40 secondi!
Com'è possibile? Perché tanta differenza?

+15

Si comincia 4096 le discussioni, le altre code 4096 compiti in una coda .. non sta misurando qualcosa di diverso da quello. Inutile .. –

risposta

30

I due non sono la stessa cosa.

Quando si utilizza Task.Factory.StartNew, si sta pianificando un'attività da eseguire su ThreadPool. Quando crei un nuovo Thread, devi creare e iniziare una nuova discussione.

Nel primo caso, i thread sono già stati creati e riutilizzati. Ciò causa un sovraccarico nella pianificazione delle attività, in quanto i thread non devono essere creati ogni iterazione.

Si noti che il comportamento non è lo stesso, tuttavia. Quando si crea un thread separato, ogni attività ottiene il proprio thread. Iniziano tutti subito. Quando si utilizza Task.Factory.StartNew, vengono inseriti nello scheduler per l'esecuzione su ThreadPool, che (potenzialmente) limiterà il numero di thread simultanei avviati. Questo di solito è una buona cosa, in quanto impedisce che si verifichino fenomeni di sovrasfruttamento.

+0

Quindi, se utilizzo Task è possibile che esegua il delegato specificato uno alla volta; vale a dire solo quando il precedente è completato, la classe Task inizia il prossimo? – Nick

+0

[Task.ContinueWith] (http://msdn.microsoft.com/en-us/library/dd235663.aspx): 'var t = Task.Factory.StartNew (...). ContinueWith (...)' . – user7116

+0

@Nick Puoi usare una continuazione, o, se vuoi bloccare, chiama '.Wait()' o '.Result' su' Task'/'Task '. Detto questo, se si desidera elaborare gli articoli * nell'ordine *, si potrebbe voler vedere 'BlockingCollection ' e creare invece uno scenario produttore/consumatore. –

0

Task.Factory.StartNew() non avvia immediatamente un'attività, ma lo pianifica in modo che TaskScheduled sia in grado di avviarlo un po 'più tardi (dipende dal numero di thread/attività disponibili).

MSDN dicendo che dopo il sistema operativo Thread.Start() è possibile pianificarlo per l'esecuzione, le interazioni con il sistema operativo sono molto più lente rispetto a TaskScheduler di .NET Framework ma non in tale grado.

E torna al tuo esempio, 0xFFF == 4095, quindi stai pianificando 4095 thread e ci vogliono 40 secondi. 102 thread in un secondo è un tempismo abbastanza buono! :)

4

Ogni volta che si avvia uno Task, esso entra in un pool per essere servito da un numero di thread, molti dei quali possono essere creati. Esiste un rapporto M:N di attività sui thread nel pool.

Ogni volta che si avvia uno Thread viene creato un nuovo thread e tutto il sovraccarico associato alla creazione del thread. Poiché stai creando un thread in modo esplicito, esiste un rapporto 1: 1 di thread.

Quanto più il rapporto tra attività e thread raggiunge 1, l'avvio di attività "lento" richiederà. In realtà, il ThreadPool assicura il rapporto rimane molto superiore a 1.

0

Calling Task.Factory.StartNew non significa necessariamente creare un nuovo thread, che sono gestiti dal TaskScheduler in base al numero di core, ecc la macchina dispone che esegue il codice.

Se si pianifica (chiamando lo Task.Factory.StartNew) più attività di quelle che possono essere eseguite contemporaneamente, verranno accodate ed eseguite man mano che saranno disponibili più risorse.

1

Si è verificato un problema con il test, in quanto non si attende la fine di ogni thread/attività.

L'attività utilizza una coda, quindi è molto più veloce per creare un'attività che una discussione.

Scommetto che anche se si aspetta che termini/discussioni finiscano, l'utilizzo di un'attività è più veloce. L'overhead di creare e quindi distruggere un Thread è alto. Ecco perché è stata creata la Task.Factory!

Problemi correlati