Mam pewien kod, który po wywołaniu wywołania usługi internetowej, kwerendy bazy danych i pobiera wartość z lokalnej pamięci podręcznej. Następnie łączy wartości zwracane z tych trzech działań, aby uzyskać wynik. Zamiast kolejno wykonywać te czynności, chcę je wykonywać asynchronicznie równolegle. Oto niektóre atrapa/przykładowy kod:C# wątek asynchroniczny problem
var waitHandles = new List<WaitHandle>();
var wsResult = 0;
Func<int> callWebService = CallWebService;
var wsAsyncResult = callWebService.BeginInvoke(res => { wsResult = callWebService.EndInvoke(res); }, null);
waitHandles.Add(wsAsyncResult.AsyncWaitHandle);
string dbResult = null;
Func<string> queryDB = QueryDB;
var dbAsyncResult = queryDB.BeginInvoke(res => { dbResult = queryDB.EndInvoke(res); }, null);
waitHandles.Add(dbAsyncResult.AsyncWaitHandle);
var cacheResult = "";
Func<string> queryLocalCache = QueryLocalCache;
var cacheAsyncResult = queryLocalCache.BeginInvoke(res => { cacheResult = queryLocalCache.EndInvoke(res); }, null);
waitHandles.Add(cacheAsyncResult.AsyncWaitHandle);
WaitHandle.WaitAll(waitHandles.ToArray());
Console.WriteLine(string.Format(dbResult, wsResult, cacheResult));
Problemem jest to, że ostatnia linia generuje błąd, ponieważ dbResult jest jeszcze zerowa, kiedy zostanie wykonany. Jak tylko queryDB.EndInvoke zostanie wywołany, WaitHandle zostanie zasygnalizowane i wykonanie będzie kontynuowane, ZANIM wynik queryDB.EndInvoke zostanie przypisany do dbResult. Czy jest to elegancki/elegancki sposób wokół tego?
Uwaga: Należy dodać, że wpływa to na dbResult tylko dlatego, że queryDB jest ostatnim znakiem oczekiwania, który ma być sygnalizowany.
Aktualizacja: Podczas przyjąłem odpowiedź Filipa, który jest wielki, w następstwie uwag Andrey, powinniśmy dodać, że to działa również:
var waitHandles = new List<WaitHandle>();
var wsResult = 0;
Func<int> callWebService = CallWebService;
var wsAsyncResult = callWebService.BeginInvoke(null, null);
waitHandles.Add(wsAsyncResult.AsyncWaitHandle);
string dbResult = null;
Func<string> queryDB = QueryDB;
var dbAsyncResult = queryDB.BeginInvoke(null, null);
waitHandles.Add(dbAsyncResult.AsyncWaitHandle);
var cacheResult = "";
Func<string> queryLocalCache = QueryLocalCache;
var cacheAsyncResult = queryLocalCache.BeginInvoke(null, null);
waitHandles.Add(cacheAsyncResult.AsyncWaitHandle);
WaitHandle.WaitAll(waitHandles.ToArray());
var wsResult = callWebService.EndInvoke(wsAsyncResult);
var dbResult = queryDB.EndInvoke(dbAsyncResult);
var cacheResult = queryLocalCache.EndInvoke(cacheAsyncResult);
Console.WriteLine(string.Format(dbResult, wsResult, cacheResult));
Brak odpowiedzi, ale aktualizacja do Fx4 znacznie ułatwiłaby to. –