Szukam uzasadnienia, dlaczego CancellationToken
struktura .NET została wprowadzona jako dodatek do CancellationTokenSource
klasy. Rozumiem, jak należy używać interfejsu API, ale chcę również zrozumieć, dlaczego jest tak zaprojektowany.
To znaczy, dlaczego mamy:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts.Token);
...
public void SomeCancellableOperation(CancellationToken token) {
...
token.ThrowIfCancellationRequested();
...
}
zamiast bezpośredniego przekazywania, CancellationTokenSource
jak:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts);
...
public void SomeCancellableOperation(CancellationTokenSource cts) {
...
cts.ThrowIfCancellationRequested();
...
}
Czy jest to optymalizacja wydajności oparta na fakcie, że sprawdzanie stanu anulowania odbywa się częściej niż przekazywanie tokenu?
Więc to CancellationTokenSource
może śledzić i aktualizować CancellationTokens
, a dla każdego tokena kontrola anulowania jest lokalnym dostępem do pola?
Biorąc pod uwagę, że zmienny bool bez blokowania jest wystarczający w obu przypadkach, nadal nie rozumiem, dlaczego miałoby to być szybsze.
Dzięki!
źródło
Miałem dokładne pytanie i chciałem zrozumieć uzasadnienie tego projektu.
Zaakceptowana odpowiedź miała dokładnie prawidłowe uzasadnienie. Oto potwierdzenie od zespołu, który zaprojektował tę funkcję (moje podkreślenie):
Link: .NET 4 Cancellation Framework
Moim zdaniem to, że
CancellationToken
można tylko obserwować stan i go nie zmieniać, jest niezwykle krytyczne. Możesz rozdać token jak cukierek i nigdy nie martwić się, że ktoś inny niż ty go anuluje. Chroni Cię przed wrogim kodem stron trzecich. Tak, szanse są niewielkie, ale osobiście podoba mi się ta gwarancja.Uważam również, że sprawia, że API jest czystsze, pozwala uniknąć przypadkowych pomyłek i promuje lepsze projektowanie komponentów.
Spójrzmy na publiczne API dla obu tych klas.
Jeśli miałbyś je połączyć, pisząc LongRunningFunction, zobaczę metody takie jak te wielokrotne przeciążenia „Anuluj”, których nie powinienem używać. Osobiście nienawidzę również widzieć metody Dispose.
Myślę, że obecny projekt klasy jest zgodny z filozofią „dołu sukcesu”, prowadzi programistów do tworzenia lepszych komponentów, które radzą sobie z
Task
anulowaniem, a następnie łączy je na różne sposoby, tworząc skomplikowane przepływy pracy.Pozwól, że zadam Ci pytanie, czy zastanawiałeś się, jaki jest cel tokena. To nie miało dla mnie sensu. A potem przeczytałem Anulowanie w zarządzanych wątkach i wszystko stało się krystalicznie jasne.
Uważam, że projekt ramy anulowania w TPL jest absolutnie na najwyższym poziomie.
źródło
CancellationTokenSource
może faktycznie zainicjować żądanie anulowania na swoim powiązanym tokenie (token nie może tego zrobić sam): CancellationToken ma ten wewnętrzny konstruktor:internal CancellationToken(CancellationTokenSource source) { this.m_source = source; }
i ta właściwość:public bool IsCancellationRequested { get { return this.m_source != null && this.m_source.IsCancellationRequested; } }
CancellationTokenSource używa wewnętrznego konstruktora, więc token ma odwołanie do źródło (m_source)Są oddzielne nie ze względów technicznych, ale semantycznych. Jeśli spojrzysz na implementację
CancellationToken
pod ILSpy, zobaczysz, że jest to tylko opakowanieCancellationTokenSource
(a zatem nie ma innej wydajności pod względem wydajności niż przekazywanie referencji).Zapewniają to oddzielenie funkcji, aby uczynić rzeczy bardziej przewidywalnymi: kiedy przekazujesz metodę a
CancellationToken
, wiesz, że nadal jesteś jedyną osobą, która może ją anulować. Jasne, metoda może nadal rzucaćTaskCancelledException
, aleCancellationToken
sama - i wszelkie inne metody odwołujące się do tego samego tokenu - pozostaną bezpieczne.źródło
CancellationTokenSource
. Można by pomyśleć, że możesz po prostu powiedzieć „nie rób tego”, ale ludzie (w tym ja!) I tak czasami robią te rzeczy, aby dostać się do jakiejś ukrytej funkcjonalności, i tak się stanie. Przynajmniej taka jest moja obecna teoria.CancellationToken
Jest struct tak wiele egzemplarzy może istnieć ze względu na przepuszczenie go wraz z metodami.Te
CancellationTokenSource
zestawy stan wszystkich kopii tokena podczas wywoływaniaCancel
od źródła. Zobacz tę stronę MSDNPrzyczyną projektu może być tylko kwestia oddzielenia problemów i szybkości konstrukcji.
źródło
To
CancellationTokenSource
jest „rzecz”, która powoduje anulowanie rezerwacji z dowolnego powodu. Potrzebuje sposobu na „wysłanie” tego anulowania do wszystkichCancellationToken
wydanych. W ten sposób, na przykład, ASP.NET może anulować operacje, gdy żądanie zostanie przerwane. Każde żądanie ma przesłanieCancellationTokenSource
anulowania do wszystkich wydanych tokenów.To świetne rozwiązanie do testowania jednostkowego BTW - utwórz własne źródło tokenu anulowania, uzyskaj token, wywołaj
Cancel
źródło i przekaż token do kodu, który ma obsługiwać anulowanie.źródło