private void RunAsync()
{
string param = "Hi";
Task.Run(() => MethodWithParameter(param));
}
private void MethodWithParameter(string param)
{
}
modificare
A grande richiesta devo notare che il Tasklancio verrà eseguito in parallelo con il thread chiamante. Assumendo l'impostazione predefinita, TaskSchedulerverrà utilizzato .NET ThreadPool. Ad ogni modo, questo significa che è necessario tenere conto di qualsiasi parametro passato a Taskcome potenzialmente accessibile da più thread contemporaneamente, rendendoli condivisi. Ciò include accedervi sul thread chiamante.
Nel mio codice sopra quel caso è del tutto discutibile. Le stringhe sono immutabili. Ecco perché li ho usati come esempio. Ma dì che non stai usando un String...
Una soluzione è usare asynce await. Questo, per impostazione predefinita, catturerà il SynchronizationContextthread chiamante e creerà una continuazione per il resto del metodo dopo la chiamata a awaite lo collegherà al creatoTask . Se questo metodo è in esecuzione sul thread della GUI WinForms, sarà di tipo WindowsFormsSynchronizationContext.
La continuazione verrà eseguita dopo essere stata postata di nuovo nell'acquisizione SynchronizationContext, di nuovo solo per impostazione predefinita. Quindi tornerai sul thread con cui hai iniziato dopo la awaitchiamata. Puoi cambiarlo in vari modi, in particolare usando ConfigureAwait. In breve, il resto di quel metodo non continuerà fino a dopo il Taskha completato su un altro thread. Ma il thread chiamante continuerà a essere eseguito in parallelo, ma non il resto del metodo.
Questa attesa per completare l'esecuzione del resto del metodo può o non può essere desiderabile. Se nulla in quel metodo accede successivamente ai parametri passati al fileTask potresti non volerlo utilizzare awaitaffatto.
O forse usi questi parametri molto più avanti nel metodo. Non c'è motivo di farlo awaitimmediatamente perché potresti continuare a lavorare in sicurezza. Ricorda, puoi memorizzare il Taskrestituito in una variabile e awaitsu di essa successivamente, anche con lo stesso metodo. Ad esempio, una volta che è necessario accedere in modo sicuro ai parametri passati dopo aver svolto un po 'di altro lavoro. Anche in questo caso, non non è necessario awaitsulla Taskdestra quando lo si esegue.
Ad ogni modo, un modo semplice per rendere questo thread-safe rispetto ai parametri passati Task.Runè farlo:
Devi prima decorare RunAsynccon async:
private async void RunAsync()
Nota importante
Preferibilmente il metodo contrassegnato non dovrebbe restituire nullo, come menzionato nella documentazione collegata. L'eccezione comune a questo è gestori di eventi come i clic sui pulsanti e simili. Devono tornare nulli. Altrimenti cerco sempre di restituire un o quando uso . È una buona pratica per diversi motivi.async TaskTask<TResult>async
Ora puoi awaiteseguire il Tasksimile di seguito. Non puoi usare awaitsenza async.
await Task.Run(() => MethodWithParameter(param));
Quindi, in generale, se si awaitesegue l'attività, è possibile evitare di trattare i parametri passati come una risorsa potenzialmente condivisa con tutte le insidie di modificare qualcosa da più thread contemporaneamente. Inoltre, attenzione alle chiusure . Non li tratterò in modo approfondito, ma l'articolo collegato fa un ottimo lavoro.
Nota a margine
Un po 'fuori tema, ma fai attenzione a usare qualsiasi tipo di "blocco" sul thread della GUI di WinForms perché è contrassegnato con [STAThread]. Utilizzandoawait non bloccherà affatto, ma a volte lo vedo usato insieme a una sorta di blocco.
"Block" è tra virgolette perché tecnicamente non è possibile bloccare il thread della GUI di WinForms . Sì, se usi lockil thread della GUI di WinForms continuerà a pompare messaggi, nonostante tu pensi che sia "bloccato". Non è.
Ciò può causare problemi bizzarri in casi molto rari. Uno dei motivi per cui non vuoi mai usare un lockquando dipingi, per esempio. Ma questo è un caso marginale e complesso; tuttavia l'ho visto causare problemi folli. Quindi l'ho annotato per completezza.