2013-03-07 15 views
6

Ho una piccola query.Scrittura di metodi multithread utilizzando async/attendo in .Net 4.5

Ammetto che non ho usato il multithreading molto prima. Net 4.5, ma con la nuova funzionalità async/await ho deciso di provarlo. Ho iniziato a sperimentarlo e tutto sembra a posto, ma non sono riuscito a trovare una soluzione per il mio "problema" in nessun punto del web.

Così tutti spiegano come await può essere utilizzato con i metodi recentemente trasformato della piattaforma .Net (ad esempio WriteAsync(), ReadAsync() ecc ...), ma se volevo usarlo per i miei metodi? Ad esempio, diciamo che sto eseguendo un calcolo estremamente costoso e voglio che tutti i miei 4 core lavorino su di esso. Avrei qualcosa di simile a questo:

async Task DoLotsOfWork<T>(T[] data, int start, int end) 
{ 
    //Do very expensive work 
} 

Ma dal momento che non ho una parola chiave await lì, il metodo è solo trattato come uno sincrono. Vorrei chiamarlo 4 volte dall'esterno in modo che possa funzionare su tutti i miei core, mentre visualizzo qualcosa di sensato all'utente (ad esempio "Please wait ..."). L'unica soluzione che sono riuscito a capire è stata l'aggiunta di await Task.Yield(); all'inizio del metodo. Qualcosa del genere:

async Task DoLotsOfWork<T>(T[] data, int start, int end) 
{ 
    await Task.Yield(); 
    //Do very expensive work 
} 

In tal caso, il metodo si comporterebbe come mi sarei aspettato. Ma c'è una soluzione migliore per questo? Sento che dovrebbe essere più facile/più ragionevole di scrivere esattamente quella riga di codice. Capisco che posso creare un oggetto Task/Thread e chiamare il metodo Start(), ma questo richiede ancora più lavoro. Ho solo pensato che con la nuova funzionalità asincrona/attesa questo genere di cose sarebbe stato più semplice.

+4

Il nuovo asincrono/attendono modello non offre multithreading. Offre solo un codice più pulito per la gestione delle operazioni che bloccano il thread corrente. – Freeman

+0

Le parole chiave non significano "usa tutti i miei core". Dicono solo al compilatore e al runtime che un'operazione può essere eseguita su un thread sperato. Se ci sono 4 operazioni che possono essere eseguite contemporaneamente potrebbero essere eseguite su 4 core diversi. – Jodrell

+0

Vuoi dare un'occhiata a questa [asincronia vs concorrenza] (http://stackoverflow.com/questions/4844637/che-è-la-differenza-della-concorrenza-parallelismo-e-metodiosincroni), asincrona l'attesa NON aiuta con il multithreading. È utile anche per macchine single core. – Aron

risposta

13

Quindi, per iniziare con voi avrete bisogno di un metodo che fa il lavoro molto costoso in modo sincrono:

public void DoLotsOfWork<T>(T[] data, int start, int end) 
{ 
    Thread.Sleep(5000);//placeholder for real work 
} 

Poi possiamo usare Task.Run per avviare più istanze di questo lavoro in un thread ThreadPool.

List<Task> tasks = new List<Task>(); 
for(int i = 0; i < 4; i++) 
{ 
    tasks.Add(Task.Run(()=>DoLotsOfWork(data, start, end)); 
} 

Poi possiamo fare un'attesa non-blocking fino a quando tutti sono fatto:

await Task.WhenAll(tasks); 
+0

In alternativa, utilizzare la classe 'Parallel', che * è * progettata per l'elaborazione parallela. –

+2

@StephenCleary il problema è che il metodo parallelo blocca fino a quando i risultati non sono terminati, quindi si finisce per dover lanciare 'Parallel.For' o' Foreach' in un 'Task.Esegui »se si è attualmente in un contesto di interfaccia utente e non è possibile bloccare fino al completamento delle attività. – Servy

+1

@Servy: vero. Ma il vantaggio di 'Parallel' è che partizionerà automaticamente il lavoro per sfruttare al meglio i core disponibili. Come hai detto, puoi racchiuderlo in 'Task.Run' per ottenere un' Task' che rappresenti un lavoro parallelo. –