2014-11-17 11 views
8

Ich arbeite an einem Web-API-Projekt, das den verwalteten Cache-Dienst von Azure zum Zwischenspeichern von Datenbankergebnissen im Speicher verwendet, um Antwortzeiten zu verbessern und doppelten Datenverkehr zur Datenbank zu verringern. Beim Versuch, ein neues Objekt in den Cache zu stellen, wird gelegentlich eine cache-spezifische Ausnahme mit dem Code DataCacheErrorCode.RetryLater ausgelöst. Natürlich, um später erneut zu versuchen, ohne auf diese Methode zu blockieren, habe ich es async und await Task.Delay gemacht, um es kurze Zeit später erneut zu versuchen. Zuvor hatte ein Entwickler eine Thread.Sleep darin hartcoded, die wirklich Anwendungsleistung schädigte.Überlegungen zum Warten auf einen Task in einer asynchronen Methode

Die Signatur der Methode sieht nun dazu etwas ähnliches:

public static async Task Put(string cacheKey, object obj) 

Nach dieser Änderung, die ich bekomme ~ 75 Compiler-Warnungen von allen anderen Orten in der Anwendung, die die ehemals synchrone Version von Put angibt, genannt:

Da dieser Aufruf nicht erwartet wird, wird die Ausführung der aktuellen Methode fortgesetzt, bevor der Aufruf abgeschlossen wird. Erwägen Sie, den Operator 'abwarten' auf das Ergebnis des Aufrufs anzuwenden.

In diesem Fall, da Put nichts zurückliefert, macht es Sinn für mich diese Operation fire-and-forget wie ich aus irgendeinem Grund Durchführung des Verfahrens blockieren nicht sehen zu lassen, die aufgerufen es. Ich frage mich nur, ob es irgendwelche Gefahren oder Fallstricke für das Erlauben einer Menge dieser Feuer-und-vergessen Task s gibt, die im Hintergrund laufen, da Put ziemlich häufig genannt werden kann. Oder sollte ich sowieso warten, da ich 99% der Zeit nicht den Wiederholungsfehler bekomme und die Task wird fast sofort fertig. Ich möchte nur sicherstellen, dass ich keine Strafen für zu viele Threads (oder so ähnlich) bekomme.

Antwort

6

Wenn es eine Chance ist Put wird jede andere Ausnahme für jede Art von Grund werfen, und Sie nicht verwenden await Put jedes Mal, wenn Sie ein Objekt in den Cache sind Einfügen, werden die Ausnahmen in der zurück Task geschluckt werden, die wird nicht erwartet. Wenn Sie .NET 4.0 verwenden, wird diese Ausnahme innerhalb des Finalizers von Task. erneut ausgelöst. Wenn Sie .NET 4.5 verwenden, wird es einfach ignoriert (und das ist möglicherweise nicht wünschenswert).

sicherstellen möchten, dass ich nicht mit zu viele Threads oder so etwas keine Strafen bin entstehen.

Ich sage nur, um die Dinge klar zu machen. Wenn Sie Task.Delay verwenden, werden keine neuen Threads gedreht. A Task ist nicht immer gleich einem neuen Thread, der gesponnen wird. Speziell hier Task.Delay intern verwendet eine Timer, so gibt es keine Thread-Overheads (außer für den Thread, der derzeit verzögert wird, wenn Sie await verwenden).

+0

Danke für das gute Feedback. Derzeit werden alle Ausnahmen außer RetryLater abgefangen und ordnungsgemäß protokolliert, und wir befinden uns in .NET 4.5, so dass ich zuversichtlich bin, diese Aufgaben zu aktivieren und zu vergessen. –

+0

Technisch Timer verwendet einen [separaten] Thread aus einem Thread-Pool, also Task.Delay() – alexm

+2

@alexm Es verwendet einen Thread-Pool-Thread für eine sehr kurze Zeit nach Ablauf der Zeit, um den Handler auszuführen. Es wird kein Thread-Thread während des Wartens konsumiert. Dies bedeutet, dass ein Thread nur dann verwendet wird, wenn er produktive Arbeit hat, die genau das ist, was Sie wollen (und nicht vermeiden können). – Servy

2

Die Warnung sagt Ihnen, dass Sie Feuer bekommen und das Verhalten an einem Ort vergessen, an dem Sie nicht wirklich feuern und vergessen möchten. Wenn Sie wirklich feuern und vergessen möchten und kein Problem mehr haben, ohne jemals zu wissen, wann der Vorgang abgeschlossen ist oder ob er erfolgreich abgeschlossen wurde, können Sie die Warnung ignorieren.

+0

+ 1; Um die Methode als explizit "fire and forget" zu markieren, kann der Rückgabetyp von asynchroner Task in asynchron void geändert werden. – alexm

+0

@alexm async void nicht schön mit Web-API platziert Ich habe Ausnahmen in der Vergangenheit erhalten, die darauf hindeuten, dass es nicht erlaubt ist, wenn ich es verwenden wollte –

+1

@alexm Das würde es so machen, dass die einzige Möglichkeit die Methode jemals könnte man nennt sich durch Feuer und Vergessen, was anders ist als das Erlauben der zu erwartenden Methode, aber einfach das Durchführen von Feuer und das Vergessen der Semantik in bestimmten Situationen für bestimmte Anrufer. – Servy

0

Empfohlene ASP.NET Weg ist

HostingEnvironment.QueueBackgroundWorkItem(WorkItem); 

... 

async Task WorkItem(CancellationToken cancellationToken) 
{ 
    try { await ...} catch (Exception e) { ... } 
} 

BTW Nicht Fangen/Wiederwurf auf anderen Thread dann kann ASP.NET Thread verursachen Server-Prozess

1

Ein negatives Ergebnis der Freigabe einer Aufgabe unawaited zu laufen abgestürzt/neu gestartet werden, ist die Compiler-Warnungen selbst - 75 Compiler-Warnungen sind ein Problem an sich und sie verbergen echte Warnungen.

Wenn Sie den Compiler signalisieren wollen, dass Sie absichtlich nicht mit dem Ergebnis der Aufgabe etwas zu tun, können Sie eine einfache Erweiterung Methode verwenden, die nichts tut, sondern erfüllt den Wunsch des Compilers für Ausführlichkeit.

// Do nothing. 
public static void Release(this Task task) 
{ 
} 

Jetzt können Sie

UpdateCacheAsync(data).Release(); 

ohne Compiler-Warnungen nennen.

https://gist.github.com/lisardggY/396aaca7b70da1bbc4d1640e262e990a

Verwandte Themen