2015-06-13 8 views
7

Próbuję użyć Task.WaitAll na liście zadań. Chodzi o to, że zadania to asynchroniczna lambda, która łamie się, tak jak nigdy nie czeka.Task.Factory.StartNew z asynchroniczną wartością lambda i Task.WaitAll

Oto blok przykładowy kod:

List<Task> tasks = new List<Task>(); 
tasks.Add(Task.Factory.StartNew(async() => 
{ 
    using (dbContext = new DatabaseContext()) 
    { 
     var records = await dbContext.Where(r => r.Id = 100).ToListAsync(); 
     //do long cpu process here... 
    } 
} 
Task.WaitAll(tasks); 
//do more stuff here 

nie czekać z powodu lambda asynchronicznym. Więc jak mam oczekiwać operacji I/O w mojej lambda?

+0

Co jest punktem startu zadanie na innym wątku, jeśli pierwszą rzeczą, którą zrobisz po uruchomieniu jest blok w wywołaniu 'Task.WaitAll'? Otrzymasz lepszą wydajność, pozbawiając się 'ToListAsync' i czyniąc ją' ToList' i uruchamiając ją synchronicznie. (lub jeśli chcesz używać 'ToListAsync', musisz użyć asynchronizacji aż do stosu wywołań. –

Odpowiedz

10

Task.Factory.StartNew nie rozpoznaje async delegatów, gdyż nie ma przeciążenia, który przyjmuje funkcję przekazujących Task.

Ten oraz inne przyczyny (patrz StartNew is dangerous) Dlatego należy używać Task.Run tutaj:

tasks.Add(Task.Run(async() => ... 
+0

To zadziałało ... trochę. Nie jestem pewien problemu, ale otrzymuję zadanie anulowane wyjątek próbuję Zwróć ciąg. Wydaje się, jak inny problem, więc mam zamiar rozpocząć nowy wątek SO.Dzięki. –

+2

Zbyt złe Task.run nie daje 'TaskCreationOptions' –

+0

' Task.Factory.StartNew (Func funkcja 'wydaje być dostępne w .NET Standard 1.6 - jedna z nich może być zmuszona do 'Unwrap()' wynikowego 'Task'tego :) :) – urbanhusky

-1

należy użyć metody Task.ContinueWith. Podoba Ci się to

List<Task> tasks = new List<Task>(); 
tasks.Add(Task.Factory.StartNew(() => 
{ 
    using (dbContext = new DatabaseContext()) 
    { 
     return dbContext.Where(r => r.Id = 100).ToListAsync().ContinueWith(t => 
      { 
       var records = t.Result; 
       // do long cpu process here... 
      }); 
     } 
    } 
} 
0

Można to zrobić w ten sposób.

void Something() 
    { 
     List<Task> tasks = new List<Task>(); 
     tasks.Add(ReadAsync()); 
     Task.WaitAll(tasks.ToArray()); 
    } 

    async Task ReadAsync() { 
     using (dbContext = new DatabaseContext()) 
     { 
      var records = await dbContext.Where(r => r.Id = 100).ToListAsync(); 
      //do long cpu process here... 
     } 
    } 
+0

To była prawie dobra odpowiedź. Nie powinieneś blokować 'Task.WaitAll' jeśli używasz' async', ponieważ możesz łatwo zakleić. –

+0

WaitAll jest tym, co Jakub chciał zrobić zgodnie z pytaniem. – hebinda

9

nie czekać z powodu lambda asynchronicznym. Więc jak mam oczekiwać na operacje we/wy w mojej lambda?

Powodem Task.WaitAll nie czekać na zakończenie prac prezentowanych przez IO async lambda dlatego Task.Factory.StartNew faktycznie zwraca Task<Task>. Ponieważ twoja lista to List<Task> (i Task<T> wywodzi się z Task), czekasz na zewnętrzne zadanie rozpoczęte przez StartNew, podczas gdy ignoruje wewnętrzny stworzony przez asynchroniczną lambdę. To dlatego mówią, że Task.Factory.StartNew jest niebezpieczna w odniesieniu do asynchronizacji.

Jak możesz to naprawić? Można jawnie wywołać Task<Task>.Unwrap() w celu uzyskania wewnętrznej zadanie:

List<Task> tasks = new List<Task>(); 
tasks.Add(Task.Factory.StartNew(async() => 
{ 
    using (dbContext = new DatabaseContext()) 
    { 
     var records = await dbContext.Where(r => r.Id = 100).ToListAsync(); 
     //do long cpu process here... 
    } 
}).Unwrap()); 

Albo jak mówili inni, można nazwać Task.Run zamiast:

tasks.Add(Task.Run(async() => /* lambda */); 

Ponadto, ponieważ chcesz być robienia rzeczy prawo, „ll chcesz użyć Task.WhenAll, dlaczego jest asynchronicznie waitable zamiast Task.WaitAll który synchronicznie bloki:

await Task.WhenAll(tasks); 
Powiązane problemy