2012-02-17 17 views
7

Sto cercando di capire quando utilizzare TaskEx.Run. Ho fornito due esempi di codice che ho scritto di seguito che producono lo stesso risultato. Quello che non riesco a capire è perché vorrei prendere la Task.RunExTaskEx.RunEx approccio , sono sicuro che ci sia una buona ragione e speravo che qualcuno mi potrebbe riempire.Quando utilizzare TaskEx.Run vs. TaskEx.RunEx

async Task DoWork(CancellationToken cancelToken, IProgress<string> progress) 
{ 
    int i = 0; 
    TaskEx.RunEx(async() => 
     { 
      while (!cancelToken.IsCancellationRequested) 
      { 
       progress.Report(i++.ToString()); 
       await TaskEx.Delay(1, cancelToken); 
      } 
     }, cancelToken); 
} 
private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    if (button.Content.ToString() == "Start") 
    { 
     button.Content = "Stop"; 
     cts.Dispose(); 
     cts = new CancellationTokenSource(); 
     listBox.Items.Clear(); 
     IProgress<string> progress = new Progress<string>(s => 
     { 
      listBox.Items.Add(s); 
      listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); 
     }); 
     DoWork(cts.Token, progress); 
    } 
    else 
    { 
     button.Content = "Start"; 
     cts.Cancel(); 
    } 
} 

posso ottenere gli stessi risultati like so

async Task DoWork(CancellationToken cancelToken) 
    { 
     int i = 0; 
     while (!cancelToken.IsCancellationRequested) 
     { 
      listBox.Items.Add(i++); 
      listBox.ScrollIntoView(listBox.Items[listBox.Items.Count - 1]); 
      await TaskEx.Delay(100, cancelToken); 

     } 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     if (button.Content.ToString() == "Start") 
     { 
      button.Content = "Stop"; 
      cts.Dispose(); 
      cts = new CancellationTokenSource(); 
      listBox.Items.Clear(); 
      DoWork(cts.Token); 
     } 
     else 
     { 
      button.Content = "Start"; 
      cts.Cancel(); 
     } 
    } 
+0

Il thread precedente è una discussione sui motivi per TaskEx.RunEx, è tutto relativo alle modifiche che non possono essere inserite nella funzionalità di base di .NET per il CTP, ma sarà integrato correttamente per la versione finale –

+0

Operazione 'modificata .RunEx' a 'TaskEx.RunEx' Non esiste né' Run() 'né' RunEx() 'nella classe' Task' Async CTP. Sono entrambi in 'TaskEx'. Correggimi, se ho torto le code –

risposta

0

Task.Run genera un nuovo thread nella maggior parte degli scenari come ho capito.

È importante notare che semplicemente perché si contrassegna un metodo come asincrono e si utilizzano gli attendenti, questo NON significa (necessariamente) che si stanno creando nuovi thread, i completamenti sono pianificati sul thread di esecuzione SAME da cui sono stati chiamati in molti casi.

Il trucco qui ha a che fare con SchedulingContext. Se è impostato per un apartment con multithreading, quindi delegherete i completamenti a thread validi sul threadpool. Se ti trovi in ​​un appartamento singlet come tutti i codici UF di WPF e WinForms, allora tornerà al thread chiamante per il completamento consentendo di eseguire il lavoro direttamente sull'interfaccia utente senza il marshalling del thread visibile nel codice.

+0

'Task.Run' nel pool di thread, che in genere non inizia una nuova discussione. 'await' pianifica la sua continuazione al suo attuale' SynchronizationContext' o 'TaskScheduler' (non thread) - vedere la fine di [questo articolo] (http://msdn.microsoft.com/en-us/magazine/gg598924.aspx) che si applica ancora al CTP v3 (e all'ev anteprima VS11). Copro anche il contesto asincrono in [il mio post di introduzione asincrona] (http://nitoprograms.blogspot.com/2012/02/async-and-await.html).Questo contesto non ha nulla a che fare con MTA o STA, sebbene sia possibile avere un contesto che supporti STA o MTA. –

+0

Mi sento piacevolmente corretto: D – Firoso

11

Utilizzare TaskEx.Run quando si desidera eseguire il codice sincrono in un contesto di pool di thread.

Utilizzare TaskEx.RunEx quando si desidera eseguire codice asincrono in un contesto di pool di thread.

Stephen Toub ha due post del blog legati alla differenza di comportamento:

questa è solo una delle diverse opzioni che avete per creating tasks. Se non è necessario utilizzare Run/RunEx, non si dovrebbe. Utilizzare i metodi semplici async e utilizzare solo Run/RunEx se è necessario eseguire qualcosa in background.

+0

In realtà non è vero ... RunEx ha a che fare con il valore restituendo espressioni lambda ... non con asincronia. Esegui maniglie async lambda va bene. – Firoso

+2

In .Net 4.5 DP, sembra esserci solo 'Task.Run()', no 'Ex'es. – svick

+4

TaskEx è solo nel CTP. In. Net 4.5 i metodi su TaskEx sono stati integrati in Task. – Phil

1

La differenza tra i due metodi DoWork() è che il primo (che utilizza TaskEx.RunEx()) non è affatto asincrono. Esegue completamente in modo sincrono, avvia l'altra attività su un altro thread e restituisce immediatamente un Task completato. Se si è await o o Wait() su tale attività, è non attendere fino al completamento dell'attività interna.

Problemi correlati