2015-06-08 13 views
5

Czy widzisz jakieś pułapki lub problemy podczas odradzania dwóch oddzielnych zadań dla zapytania Oracle db i zapytania Active Directory, a następnie czeka na oba.Nić tła za pomocą Task.Run

Poniżej znajduje się bardzo prosty przykład zdejmowania. Zasadniczo mamy obiekt pracownika, który powstaje z fragmentów informacji z AD i z bazy danych Oracle. (Nazywane sekwencyjnie)

var partialEmployeeA=ActiveDirectoryLookup(employeeID); 

var partialEmployeeB=OracleDBLookup(employeeID); 

var finalEmployee=Merge(partialEmployeeA,partialEmployeeB); 

W tym momencie Employee obiekt został utworzony i poskładane z obu zapytań i mogą być używane. To zadziałało bez problemu, ale jeśli każde z tych połączeń było jego własnym zadaniem, czy widziałbyś jakieś problemy ze skalowanego punktu widzenia? (Z wyłączeniem wszelkich innych kwestii kodu oczywistych)

Employee partialEmployeeA; 
Employee partialEmployeeB; 

var t1 = Task.Run(() => { 
    partialEmployeeA=ActiveDirectoryLookup(employeeID); 
}); 

var t2 = Task.Run(() => { 
    partialEmployeeB=OracleDBLookup(employeeID); 
});, 

Task.WaitAll(t1, t2); 
var finalEmployee=Merge(partialEmployeeA,partialEmployeeB); 

Zrobiłem kilka testów z klasy stopera i wersji Task wraca szybciej za każdym razem (średnio: 100-120ms vs 200-250ms) i nie ma problemu, ale waśń nie wiem, jak to skalowane w systemie wielordzeniowym. Nie zrobiłem wiele z TPL, ale byłem ciekawy tego podejścia.

Odpowiedz

6

Nie widzę żadnych problemów z tym, są to różne usługi z różnymi żądaniami, które prawdopodobnie nie mają żadnego stanu.

Należy jednak pamiętać, że w obu przypadkach są 3 wątki, które są zablokowane w całej operacji asynchronicznej (I/O).

Byłoby szybciej wykonywać te operacje równolegle, wykorzystując wiele wątków. Ale to nie będzie bardziej skalowalne.

Aby to zrobić „prawo” bez blokowania wątku i korzystania z zasobów trzeba traktować te działania jako prawdziwie asynchroniczny i nie tylko na wątku tła:

var partialEmployeeATask = ActiveDirectoryLookupAsync(employeeID); 
var partialEmployeeBTask = OracleDBLookupAsync(employeeID); 

await Task.WhenAll(partialEmployeeATask, partialEmployeeBTask) 
var finalEmployee = Merge(await partialEmployeeATask, await partialEmployeeBTask); 

które wymaga zmiany API do obsługi asynchronicznej wnioski w jakiejś formie. Jeśli interfejs API nie jest pod Twoją kontrolą, może to być problem. Jeśli nie da się tego zrobić, użyj przynajmniej jeden raz Task.Run i użyj "głównego" wątku do drugiej części.

+0

Ponieważ zadania są już oczekiwane z 'await Task.WhenAll', czy nie byłoby lepiej, aby wziąć' .Result' podczas scalania, zamiast czekać na nich ponownie? Albo jeszcze lepiej, ponieważ oba zadania zwracają wyniki, czy nie możesz uzyskać wyników w postaci tablicy od wyniku 'czekaj na Task.WhenAll'? –

+0

Dziękuję bardzo za odpowiedź i3arnon. Czy możesz wyjaśnić więcej na temat blokowania wątków w porównaniu do opcji równoległej? Po prostu nie jestem zaznajomiony z efektami, które miałyby lub kiedy uniknąć tej trasy. – jdross

+0

@jdross - zobacz [MSDN: Programowanie asynchroniczne z Async i Oczekiwanie] (https://msdn.microsoft.com/en-us/library/hh191443.aspx) –

Powiązane problemy