Ich suche nach einer Begründung, warum .NET CancellationToken
struct zusätzlich zum CancellationTokenSource
Unterricht eingeführt wurde. Ich verstehe, wie die API verwendet werden soll, möchte aber auch verstehen, warum sie so konzipiert ist.
Dh warum haben wir:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts.Token);
...
public void SomeCancellableOperation(CancellationToken token) {
...
token.ThrowIfCancellationRequested();
...
}
anstatt direkt herumzugeben CancellationTokenSource
wie:
var cts = new CancellationTokenSource();
SomeCancellableOperation(cts);
...
public void SomeCancellableOperation(CancellationTokenSource cts) {
...
cts.ThrowIfCancellationRequested();
...
}
Handelt es sich um eine Leistungsoptimierung, die auf der Tatsache basiert, dass Abbruchstatusprüfungen häufiger stattfinden als das Weitergeben des Tokens?
Damit CancellationTokenSource
können Sie verfolgen und aktualisieren CancellationTokens
, und für jedes Token ist die Stornierungsprüfung ein lokaler Feldzugriff?
Angesichts der Tatsache, dass in beiden Fällen ein flüchtiger Bool ohne Verriegelung ausreicht, kann ich immer noch nicht erkennen, warum dies schneller wäre.
Vielen Dank!
quelle
Ich hatte die genaue Frage und wollte die Gründe für dieses Design verstehen.
Die akzeptierte Antwort brachte die Begründung genau richtig. Hier ist die Bestätigung des Teams, das diese Funktion entwickelt hat (Schwerpunkt Mine):
Link: .NET 4 Cancellation Framework
Meiner Meinung nach ist die Tatsache, dass
CancellationToken
man den Zustand nur beobachten und nicht ändern kann, äußerst kritisch. Sie können den Token wie eine Süßigkeit verteilen und müssen sich niemals Sorgen machen, dass jemand anderes als Sie ihn storniert. Es schützt Sie vor feindlichem Code von Drittanbietern. Ja, die Chancen stehen schlecht, aber ich persönlich mag diese Garantie.Ich habe auch das Gefühl, dass es die API sauberer macht, versehentliche Fehler vermeidet und ein besseres Komponentendesign fördert.
Schauen wir uns die öffentliche API für beide Klassen an.
Wenn Sie sie kombinieren, werden beim Schreiben von LongRunningFunction Methoden wie die mehrfachen Überladungen von 'Abbrechen' angezeigt, die ich nicht verwenden sollte. Persönlich hasse ich es, auch die Dispose-Methode zu sehen.
Ich denke, das aktuelle Klassendesign folgt der "Pit of Success" -Philosophie. Es führt Entwickler dazu, bessere Komponenten zu erstellen, die mit
Task
Stornierungen umgehen können, und sie dann auf vielfältige Weise zusammenzustellen, um komplizierte Workflows zu erstellen.Lassen Sie mich Ihnen eine Frage stellen. Haben Sie sich gefragt, was der Zweck von Token ist? Registrieren? Es ergab für mich keinen Sinn. Und dann habe ich gelesen Stornierung in verwalteten Threads und alles wurde kristallklar.
Ich glaube, dass das Cancellation Framework Design in TPL absolut erstklassig ist.
quelle
CancellationTokenSource
die Abbruchanforderung für das zugehörige Token tatsächlich initiieren kann (das Token kann dies nicht selbst tun): Das CancellationToken verfügt über diesen internen Konstruktor:internal CancellationToken(CancellationTokenSource source) { this.m_source = source; }
und diese Eigenschaft:public bool IsCancellationRequested { get { return this.m_source != null && this.m_source.IsCancellationRequested; } }
Die CancellationTokenSource verwendet den internen Konstruktor, sodass das Token auf das verweist Quelle (m_source)Sie sind nicht aus technischen, sondern aus semantischen Gründen getrennt. Wenn Sie sich die Implementierung von
CancellationToken
unter ILSpy ansehen , werden Sie feststellen, dass es sich lediglich um einen Wrapper handeltCancellationTokenSource
(und daher in Bezug auf die Leistung nicht anders ist als das Weitergeben einer Referenz).Sie bieten diese Trennung von Funktionen, um die Vorhersehbarkeit zu verbessern: Wenn Sie eine Methode a übergeben
CancellationToken
, wissen Sie, dass Sie immer noch die einzige sind, die sie abbrechen kann. Sicher, die Methode könnte immer noch ein werfenTaskCancelledException
, aber dasCancellationToken
selbst - und alle anderen Methoden, die auf dasselbe Token verweisen - würden sicher bleiben.quelle
CancellationTokenSource
. Sie würden denken, Sie könnten einfach sagen "Tu das nicht", aber Leute (einschließlich ich!) Tun diese Dinge gelegentlich trotzdem, um an versteckte Funktionen zu gelangen, und es würde passieren. Das ist zumindest meine aktuelle Theorie.Das
CancellationToken
ist eine Struktur, bei der so viele Kopien existieren könnten, weil sie an Methoden weitergegeben werden.Das
CancellationTokenSource
legt den Status ALLER Kopien eines Tokens fest, wennCancel
die Quelle aufgerufen wird. Siehe diese MSDN-SeiteDer Grund für das Design könnte nur eine Frage der Trennung von Bedenken und der Geschwindigkeit einer Struktur sein.
quelle
Das
CancellationTokenSource
ist das "Ding", das die Stornierung aus irgendeinem Grund ausstellt. Es braucht eine Möglichkeit, diese Stornierung an alle vonCancellationToken
ihr ausgestellten zu versenden . So kann beispielsweise ASP.NET Vorgänge abbrechen, wenn eine Anforderung abgebrochen wird. Jede Anfrage hat eineCancellationTokenSource
, die die Stornierung an alle von ihr ausgegebenen Token weiterleitet.Dies ist ideal für Unit-Tests. Übrigens: Erstellen Sie Ihre eigene Quelle für Stornierungstoken, holen Sie sich ein Token, rufen Sie
Cancel
die Quelle auf und übergeben Sie das Token an Ihren Code, der die Stornierung verarbeiten muss.quelle