2015-01-28 14 views
5

Mój problem polega na tym, że wywołanie czeka na tabelę.ExecuteAsync (...) na platformie Azure Storage Table wstawia żądane dane, ale nigdy się nie kończy (nie zwraca TableResult). Ten sam przypadek z operacjami InsertOrUpdate i Update. Próbowałem również różnych tabel o różnej liczbie właściwości - ten sam problem.Tabele przechowywania Azure: czekają na tabelę.ExecuteAsync (InsertOperation) działa, ale nigdy się nie kończy

Kiedy zadzwonię pod numer table.Execute (...) - wszystko działa dobrze dla każdego rodzaju operacji.

Oto mój kod - proste:

Zewnętrzne połączenia (jest on umieszczony w MVC Controller w działaniu asynchronicznym):

List<Task<ServiceResult<Boolean?>>> addPostTasks = new List<Task<Common.ServiceResult<bool?>>>();    
foreach (var userStream in userStreams) 
{ 
    Task<ServiceResult<Boolean?>> addPostTask = postsStorageSvc.AddImagePost(...); 
    postsAddImagePostTasks.Add(addPostTask); 
} 
Task.WaitAll(addPostTasks.ToArray()); 

metoda zwana:

public async Task<ServiceResult<Boolean?>> AddImagePost(...) 
{ 
ServiceResult<Boolean?> result = new ServiceResult<bool?>(null); 
try 
{ 
    PostTableEntity newPost = new PostTableEntity(streamId.ToString(), Guid.NewGuid().ToString(), creatorId, date, htmlText);    
    TableOperation insertOperation = TableOperation.Insert(newPost); 
    //Following line never ends! 
    TableResult tableResult = await this._storageTableBootstrapper.Table.ExecuteAsync(insertOperation);     
    //Following line works perfect - but is not ASYNC 
    TableResult tableResult = this._storageTableBootstrapper.Table.Execute(insertOperation); 
} 
catch (Exception ex) 
{ 
    result.Result = false; 
    result.Errors.Add("AzurePostsStorageService Unexpected error: " + ex.Message); 
} 
return result; 
} 
+0

Jak się nazywa ta metoda? –

+0

Co masz na myśli? Ten blok kodu jest w metodzie asynchronicznej, aktualizuję moje pytanie, aby wyświetlić otaczające linie. –

+0

Pokaż podpis metody i sposób jej wywołania. Czy może blokujesz go za pomocą 'Task.Result' lub' Task.Wait'? –

Odpowiedz

9

Problemem jest tutaj:

Task.WaitAll(addPostTasks.ToArray()); 

Twój sposób asynchroniczny próbuje zebrać się z powrotem do Kontekst synchronizacji ASP.NET, który utknął, ponieważ zainicjowano wywołanie blokujące za pomocą Task.WaitAll.

Zamiast tego trzeba przestrzegać asynchroniczny całą drogę wzór i używać Task.WhenAll i await na ten temat:

await Task.WhenAll(addPostTasks.ToArray); 

Stephan Cleary rozwija to w swoim blogu (który dodaje @NedStoyanov):

Innym ważnym punktem: kontekst żądania ASP.NET jest nie przywiązany do konkretnego wątku (jak kontekst UI jest), ale czy tylko zezwala na jeden wątek w danym momencie. Ten interesujący aspekt nie jest oficjalnie dokumentowany gdziekolwiek AFAIK, ale jest wymieniony w moim artykule MSDN o SynchronizationContext.

+2

Dobre informacje na temat kontekstu ASP, dobrze wiedzieć. –

4

Jest to klasyczny deadlock spowodowany przez tę linię:

Task.WaitAll(addPostTasks.ToArray()); 

spróbuj zmienić go na adres:

await Task.WhenAll(addPostTasks.ToArray()); 

Zasadniczo te Task.WaitAll blokuje wątku żądanie i nie jest w stanie zrealizować kontynuację Tasks zainicjowane przez await table.ExecuteAsync(...). Inną alternatywą jest użycie ConfigureAwait(false) na wewnętrznych zadaniach, aby uniknąć przełączania SynchronizatonContext.

await table.ExecuteAsync(...).ConfigureAwait(false); 

Można użyć ConfigureAwait(false) gdy nie wymagają, aby przełączyć się do oryginalnego SynchronizationContext. W twoim przypadku wydaje mi się, że możesz to zrobić z wszystkimi oczekiwaniami, tak jak na serwerze, i nie powinno mieć znaczenia, czy kod po await jest uruchamiany w puli wątków czy nie.

Zobacz ten artykuł Więcej szczegółów: msdn.microsoft.com/enus/magazine/jj991977.aspx

+0

Twoja odpowiedź ma to samo znaczenie, co powyżej, ale jakkolwiek tam, gdzie pierwszy Yuval Itzchakov dostarczył więcej informacji. –

+0

Tak, jego odpowiedź była lepsza. Nauczyłem się też czegoś. –

+0

OK, więc dla jasności i zrozumienia sprawy lepiej. ** Czy radzisz użyć ".ConfigureAwait (false)" we wszystkich naszych operacjach asynchronicznych, które znajdują się na szczycie stosu wykonawczego ** (jak np. Table.ExecuteAsync (...) czy nawet nasze własne asynchroniczne operacje/metody)? –

Powiązane problemy