Was ist der richtige Weg zum Abbrechen einer asynchronen operation, die nicht akzeptieren, ein CancellationToken?
Was ist die richtige Art und Weise zu kündigen?
var tcpListener = new TcpListener(connection);
tcpListener.Start();
var client = await tcpListener.AcceptTcpClientAsync();
Einfach anrufen tcpListener.Stop()
scheint eine ObjectDisposedException
und die AcceptTcpClientAsync
Methode nicht akzeptieren CancellationToken
Struktur.
Bin ich Total fehlt etwas, das offensichtlich ist?
InformationsquelleAutor Jeff | 2013-01-25
Du musst angemeldet sein, um einen Kommentar abzugeben.
Unter der Annahme, dass Sie nicht wollen, zu nennen, die
Stop
Methode auf dieTcpListener
Klasse, es gibt keine perfekte Lösung hier.Wenn es dir gut geht mit benachrichtigt werden, wenn der Betrieb nicht innerhalb eines bestimmten Zeitrahmens, sondern indem Sie den ursprünglichen Vorgang abgeschlossen ist, dann können Sie eine extension-Methode, etwa so:
Die oben ist von Stephen Toub blog-post "Wie lösche ich unkündbaren async-Operationen?".
Dem VORBEHALT, hier trägt zu wiederholen, bedeutet dies nicht eigentlich Abbrechen den Betrieb, denn es ist nicht eine überlastung der
AcceptTcpClientAsync
Methode, das dauert einCancellationToken
, es ist nicht in der Lage abgesagt werden.Das bedeutet, dass wenn das extension-Methode gibt an, dass eine Stornierung hat passieren, sind Sie stornieren das warten auf den Rückruf der ursprünglichen
Task
, nicht Abbruch der operation selbst.Zu diesem Zweck, dass ist, warum habe ich umbenannt, die Methode von
WithCancellation
zuWithWaitCancellation
um anzugeben, dass Sie die Streichung der warten, nicht die tatsächliche Handlung.Aus, es ist einfach zu verwenden, in Ihrem code:
Beachten Sie, dass müssen Sie wickeln Sie den Anruf für Ihre Kunden zu erfassen, die
OperationCanceledException
- Instanz ausgelöst, wenn das warten abgebrochen.Habe ich auch geworfen in eine
AggregateException
fangen als Ausnahmen sind verpackt, wenn man Sie wirft von asynchronen Operationen (sollten Sie testen, für sich selbst in diesem Fall).Damit bleibt die Frage, welcher Ansatz der bessere Ansatz ist angesichts der mit einer Methode wie der
Stop
Methode (im Grunde alles, was, die nicken reißt alles runter, egal was Los ist), was natürlich, hängt von den jeweiligen Umständen ab.Wenn Sie nicht teilen, die Ressource, die Sie warten auf (in diesem Fall die
TcpListener
), dann wäre es wahrscheinlich eine bessere Nutzung von Ressourcen zum Aufruf der abort-Methode und schlucken keine Ausnahmen, kommen aus Operationen, die Sie warten (Sie haben zu kippen ein bisschen, wenn Sie stop rufen und zu überwachen, dass etwas in den anderen Bereichen sind Sie warten auf eine operation). Dies fügt einige Komplexität der code, aber wenn Sie sind besorgt über die Ressourcennutzung und die Reinigung so bald wie möglich, und diese Option ist verfügbar, um Sie, dann ist dies der Weg zu gehen.Wenn Ressourcenauslastung nicht ein Thema, und Sie sind komfortabel mit einer mehr kooperativen Mechanismus, und du bist nicht Freigabe der Ressource, dann wird die Verwendung der
WithWaitCancellation
Methode ist gut. Die Vorteile hier sind, dass es sauberer code, und leichter zu pflegen.InformationsquelleAutor casperOne
Während casperOne s Antwort ist korrekt, es ist ein sauberer Potenzial mit der Umsetzung der
WithCancellation
(oderWithWaitCancellation
) Erweiterung Methode, erreicht die gleichen Ziele: dieCancellationToken
parameter.TaskContinuationOptions.ExecuteSynchronously
) und mit einemThreadPool
thread, wenn nicht (TaskScheduler.Default
), während die Beobachtung derCancellationToken
für die Stornierung.Wenn die ursprüngliche Aufgabe abgeschlossen ist, bevor die
CancellationToken
wird abgebrochen, dann wird die zurückgegebene task speichert das Ergebnis, ansonsten wird die Aufgabe abgebrochen und werfen wirdTaskCancelledException
als erwartet.completedTask.GetAwaiter().GetResult()
statt nurcompletedTask.Result
?es wirft den ersten (d.h. "realen") Ausnahme, wenn es einem im Gegensatz zu
Task.Result
wirft dieAggregateException
Ok, Super; vielen Dank. Möchten Sie auch hinzufügen
cancellationToken.ThrowIfCancellationRequested();
als erste Zeile in Ihre hilfreiche Erweiterung Methode?Sie können...obwohl es nicht wirklich notwendig. Die Fortsetzung würde sofort abgebrochen werden. Auch die Verbraucher können überrascht werden durch eine exception geworfen synchron und nicht aus der Erwartung der Aufgabe.
Die cancellationToken parameter für
ContinueWith
wird beschrieben als "DieCancellationToken
zugeordnet werden, um die neue Fortsetzung Aufgabe." Sind Sie sicher, dass dies tatsächlich Abbrechen "früher", bevor die ursprüngliche Aufgabe abgeschlossen ist? Die Dokumentation zeigt an, sonstInformationsquelleAutor i3arnon