AFAIK, wszystko, co wie, to to, że w pewnym momencie wywoływana jest jego metoda SetResult
lub SetException
metoda w celu uzupełnienia Task<T>
ekspozycji poprzez swoją Task
właściwość.
Innymi słowy, działa jako producent dla Task<TResult>
i jego ukończenia.
Widziałem tutaj przykład:
Jeśli potrzebuję sposobu, aby wykonać Func asynchronicznie i mam zadanie reprezentujące tę operację.
public static Task<T> RunAsync<T>(Func<T> function)
{
if (function == null) throw new ArgumentNullException(“function”);
var tcs = new TaskCompletionSource<T>();
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
T result = function();
tcs.SetResult(result);
}
catch(Exception exc) { tcs.SetException(exc); }
});
return tcs.Task;
}
Które mogłyby zostać wykorzystane * jeśli nie mam Task.Factory.StartNew
- Ale ja nie mam Task.Factory.StartNew
.
Pytanie:
Może ktoś proszę wyjaśnić na przykładzie scenariusza związanego bezpośrednio do TaskCompletionSource
i nie do hipotetycznej sytuacji, w której nie mam Task.Factory.StartNew
?
c#
.net
.net-4.0
task-parallel-library
taskcompletionsource
Royi Namir
źródło
źródło
Odpowiedzi:
Najczęściej go używam, gdy dostępny jest tylko interfejs API oparty na zdarzeniu ( na przykład gniazda Windows Phone 8 ):
Jest to szczególnie przydatne, gdy jest używane razem ze
async
słowem kluczowym C # 5 .źródło
SomeApiWrapper
gdzieś na to czekało, dopóki wydawca nie podniesie zdarzenia, które spowoduje zakończenie tego zadania?Microsoft.Bcl.Async
pakiet na NuGet, który pozwala naasync/await
słowa kluczowe w projektach .NET 4.0 (zalecane jest VS2012 i wyższe).Z moich doświadczeń
TaskCompletionSource
doskonale nadaje się do zawijania starych wzorów asynchronicznych do nowoczesnegoasync/await
wzoru.Najbardziej korzystnym przykładem, jaki mogę wymyślić, jest praca z nim
Socket
. Ma starą APM i wzory PW, ale nie teawaitable Task
metody, któreTcpListener
iTcpClient
mieć.Osobiście mam kilka problemów z
NetworkStream
klasą i wolę suroweSocket
. Ponieważ uwielbiam tenasync/await
wzór, stworzyłem klasę rozszerzeń,SocketExtender
która tworzy kilka metod rozszerzeniaSocket
.Wszystkie te metody wykorzystują
TaskCompletionSource<T>
do owijania wywołań asynchronicznych:I przekazać
socket
doBeginAccept
metody, tak aby uzyskać niewielki wzrost wydajności z kompilator nie trzeba podnosić lokalny parametr.Potem piękno tego wszystkiego:
źródło
Begin.. End...
instrukcje.Dla mnie klasycznym scenariuszem użycia
TaskCompletionSource
jest sytuacja, w której moja metoda niekoniecznie musi wykonywać czasochłonną operację. Pozwala nam to wybrać konkretne przypadki, w których chcielibyśmy użyć nowego wątku.Dobrym przykładem tego jest użycie pamięci podręcznej. Możesz mieć
GetResourceAsync
metodę, która szuka w pamięci podręcznej żądanego zasobu i zwraca natychmiast (bez użycia nowego wątku, przy użyciuTaskCompletionSource
), jeśli zasób został znaleziony. Tylko jeśli zasób nie został znaleziony, chcielibyśmy użyć nowego wątku i pobrać go za pomocąTask.Run()
.Przykład kodu można zobaczyć tutaj: Jak warunkowo uruchomić kod asynchronicznie za pomocą zadań
źródło
Task.FromResult
. Oczywiście, jeśli używasz 4.0 i nie maszTask.FromResult
tego, do czego użyjesz TCS, to napisz własneFromResult
.Task.FromResult
jest dostępny tylko od .NET 4.5. Wcześniej był to sposób na osiągnięcie tego zachowania.Task.Run
, wskazując, że jest w wersji 4.5+. I mój poprzedni komentarz konkretnie dotyczył .NET 4.0.W tym wpisie na blogu Levi Botelho opisuje, jak użyć
TaskCompletionSource
do napisania asynchronicznego opakowania dla procesu, abyś mógł go uruchomić i poczekać na jego zakończenie.i jego użycie
źródło
Wygląda na to nikt nie wspomniał, ale myślę, że testy jednostkowe mogą być uznane za prawdziwe życie wystarczy.
Uważam
TaskCompletionSource
być przydatna, gdy wyśmianie zależność z metody asynchronicznej.W aktualnie testowanym programie:
W testach jednostkowych:
W końcu to użycie TaskCompletionSource wydaje się kolejnym przypadkiem „obiektu Task, który nie wykonuje kodu”.
źródło
TaskCompletionSource służy do tworzenia obiektów zadań , które nie wykonują kodu. W rzeczywistych scenariuszach TaskCompletionSource jest idealny do operacji związanych z operacjami we / wy. W ten sposób uzyskasz wszystkie korzyści z zadań (np. Zwracane wartości, kontynuacje itp.) Bez blokowania wątku na czas trwania operacji. Jeśli twoja „funkcja” jest operacją związaną z We / Wy, nie jest zalecane blokowanie wątku za pomocą nowego zadania . Zamiast tego za pomocą TaskCompletionSource można utworzyć zadanie podrzędne, aby wskazać, kiedy zakończy się operacja związana z operacjami we / wy lub wystąpi błąd.
źródło
W tym poście z bloga „Parallel Programming with .NET” znajduje się przykład z prawdziwego świata . Naprawdę powinieneś to przeczytać, ale i tak jest to streszczenie.
W blogu przedstawiono dwie implementacje:
Pierwsza pokazana implementacja oparta jest na
Task<>
dwóch głównych wadach i ma dwie wady. Drugi post dotyczący implementacji pozwala na ich złagodzenie za pomocąTaskCompletionSource<>
.Oto druga implementacja:
źródło
await Task.Delay(millisecondsDelay); action(); return;
lub (w .Net 4.0)return Task.Delay(millisecondsDelay).ContinueWith( _ => action() );
Może to upraszczać rzeczy, ale źródło TaskCompletion pozwala oczekiwać na zdarzenie. Ponieważ tcs.SetResult jest ustawiany tylko po wystąpieniu zdarzenia, dzwoniący może oczekiwać na zadanie.
Obejrzyj ten film, aby uzyskać więcej informacji:
http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Lucian03-TipsForAsyncThreadsAndDatabinding
źródło
Rzeczywisty scenariusz, w którym korzystałem,
TaskCompletionSource
dotyczy implementacji kolejki pobierania. W moim przypadku, jeśli użytkownik rozpocznie 100 pobrań, nie chcę uruchamiać ich wszystkich jednocześnie, więc zamiast zwracać zlecenie strate, zwracam zadanie dołączoneTaskCompletionSource
. Po zakończeniu pobierania wątek, który działa, kolejka wykonuje zadanie.Kluczową koncepcją jest to, że rozłączam się, gdy klient prosi o uruchomienie zadania od momentu, w którym faktycznie się zaczyna. W tym przypadku, ponieważ nie chcę, aby klient miał do czynienia z zarządzaniem zasobami.
Zauważ, że możesz używać asynchronizacji / oczekiwania na .NET 4, o ile używasz kompilatora C # 5 (VS 2012+), patrz tutaj po więcej szczegółów.
źródło
Zwykłem
TaskCompletionSource
uruchamiać zadanie, dopóki nie zostanie anulowane. W tym przypadku jest to subskrybent ServiceBus, który normalnie chcę uruchamiać tak długo, jak długo działa aplikacja.źródło
TaskCompletionSource
jest do zadań, jakWaitHandle
do wątku. Dzięki temu możemy użyćTaskCompletionSource
do precyzyjnej sygnalizacji .Przykładem jest moja odpowiedź na to pytanie: opóźnienie ContentDialog po kliknięciu OK
źródło