warten Aufgaben mit Zeitlimit
Ich versuche zu schreiben, ein-Helfer-Methode, die es erlaubt mir zu übergeben, die in einer beliebigen Aufgabe und ein timeout. Wenn die Aufgabe abgeschlossen ist, bevor das Zeitlimit für einen Erfolg Delegat aufgerufen wird, andernfalls wird ein Fehler Delegat aufgerufen wird. Die Methode sieht wie folgt aus:
public static async Task AwaitWithTimeout(Task task, int timeout, Action success, Action error)
{
if (await Task.WhenAny(task, Task.Delay(timeout)) == task)
{
if (success != null)
{
success();
}
}
else
{
if (error != null)
{
error();
}
}
}
Nun diese scheint arbeiten die meisten der Zeit, aber ich wollte Sie schreiben ein paar tests als gut zu machen wissen. Dieser test, zu meiner überraschung schlägt fehl, und ruft den Fehler zu delegieren, statt den Erfolg:
var taskToAwait = Task.Delay(1);
var successCalled = false;
await TaskHelper.AwaitWithTimeout(taskToAwait, 10, () => successCalled = true, null);
Assert.IsTrue(successCalled);
Dieser test ist allerdings grün:
var taskToAwait = Task.Run(async () =>
{
await Task.Delay(1);
});
var successCalled = false;
await TaskHelper.AwaitWithTimeout(taskToAwait, 10, () => successCalled = true, null);
Assert.IsTrue(successCalled);
Wie mache ich beide tests grün? Ist meine Verwendung von Aufgabe.WhenAny falsch?
Delay(1)
ist sehr kurz (vor allem, wenn Sie Debuggen) - starten Sie auf einem separaten thread machen, es ausreichend lang für Ihre Tests zu übergeben, die meisten der Zeit. Versuchen Sie, länger verzögern, oder besser noch die Aufgabe, die es erlaubt manuell komplett synchron im test.InformationsquelleAutor user1202032 | 2016-02-26
Du musst angemeldet sein, um einen Kommentar abzugeben.
Timer sind ungenau. Standardmäßig sind in Ihrer Genauigkeit etwa 15 ms. Alles, was niedriger als der Auslöser, wird in 15ms-Intervall. Finden Sie im Zusammenhang beantworten.
Gegeben, dass Sie haben 1ms 10ms-timer und timer; beide sind etwa gleich, so erhalten Sie inkonsistente Ergebnisse gibt.
Den code, den Sie eingewickelt in
Task.Run
und Ansprüchen zu arbeiten, ist nur ein Zufall. Wenn ich mehrmals probiert, die Ergebnisse sind inkonsistent. Es schlägt manchmal aus dem gleichen Grund erwähnt.Sind Sie besser dran, die Erhöhung der timeout-oder geben Sie einfach in eine bereits abgeschlossene Aufgabe.
Beispielsweise folgende test sollte konsequent gehen. Denken Sie daran, dass Ihr test sollte konsistent sein, nicht spröde.
Für nie endende Aufgabe verwenden
TaskCompletionSource
und nicht sein Ergebnis.Auch ich empfehle Ihnen, vermeiden Sie die Verwendung
null
. Sie können geben Sie einfach die leeren Delegaten als parameter. Dann wollen Sie nicht, um null-checks verstreut über Ihre Codebasis.Ich würde schreiben Sie die helper-Methode wie:
Beachten Sie, dass die oben genannte Methode ist eine Erweiterung Methode; so können Sie rufen Sie es mit dem task-Instanz.
Sicher. Aktualisiert meine Antwort auf eine nie endende Aufgabe.
Während das core-Konzept (mit
Task.WhenAny
zu erwarten, die auf zwei Aufgaben) ist spot-on, das API herum, es fühlt sich schmutzig.Action
für den Erfolg ist chaotisch, wenn Sie brauchen, um den Draht, bis ein andererTask
von ihm - Sie würde am Ende mit hässlichen erfasst. Ich würde einfach werfen einTimeoutException
in die timeout-Szenario und behandeln erfolgreichen Abschluss als erfolgreichen Abschluss. In performance-kritischen Fällen eineTask<bool>
Gegenzug geben würde auch funktionieren (wotrue
bedeutet und erfolgreicher Abschlussfalse
bedeutet timeout).Dann gibt es auch den Umgang mit der endgültigen Fertigstellung der timed-out
Task
(siehe hier: blogs.msdn.com/b/pfxteam/archive/2012/10/05/...). Und, natürlich, vergessen Sie nichtConfigureAwait(false)
- es gibt absolut keinen Grund, nicht zu haben es Helfer oder Bibliothek Methoden.Ja genau meine Gedanken.
Task<bool>
mehr Sinn macht, als die Delegierten. Noch besser TimeoutExceptiion. Ich überlasse es OP.InformationsquelleAutor Sriram Sakthivel