caching des Ergebnisses einer [n async] -Factory-Methode, wenn es nicht @ wir

UPDATE: Stark überarbeitet, nachdem @usr darauf hingewiesen hatte, dass ich fälschlicherweise @ angenommen hatLazy<T>er Standard-Thread-Sicherheitsmodus von @ warLazyThreadSafetyMode.PublicationOnly ...

Ich möchte einen Wert faul über ein @ berechnasync Factory-Methode (d. H. Sie gibt @ zurücTask<T>) und bei Erfolg zwischenspeichern lassen. In Ausnahmefällen möchte ich, dass mir das zur Verfügung steht. Ich will aber nicht zum opfer fallendie Ausnahme Caching-Verhalten DasLazy<T> hat in seinem Standardmodus LazyThreadSafetyMode.ExecutionAndPublication)

Exception-Caching: Wenn Sie Factory-Methoden verwenden, werden Ausnahmen zwischengespeichert. Das heißt, wenn die Factory-Methode beim ersten Versuch eines Threads, auf die Value-Eigenschaft des Lazy-Objekts zuzugreifen, eine Ausnahme auslöst, wird bei jedem weiteren Versuch dieselbe Ausnahme ausgelöst. Auf diese Weise wird sichergestellt, dass jeder Aufruf der Value-Eigenschaft dasselbe Ergebnis erzielt und subtile Fehler vermieden werden, die auftreten können, wenn unterschiedliche Threads unterschiedliche Ergebnisse erzielen. Der Lazy steht für ein tatsächliches T, das sonst zu einem früheren Zeitpunkt, normalerweise während des Startvorgangs, initialisiert worden wäre. Ein Fehler an diesem früheren Punkt ist normalerweise tödlich. Wenn die Möglichkeit eines behebbaren Fehlers besteht, empfehlen wir, dass Sie die Wiederholungslogik in die Initialisierungsroutine (in diesem Fall die Factory-Methode) integrieren, genau wie Sie es tun würden, wenn Sie keine verzögerte Initialisierung verwenden würden.

Stephen Toub hat einAsyncLazy Klasse und Writeup das scheint genau richtig:

public class AsyncLazy<T> : Lazy<Task<T>>
{
    public AsyncLazy(Func<Task<T>> taskFactory) :
        base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap())
    { }

    public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}

jedoch das ist effektiv das gleiche Verhalten wie ein StandardLazy<T> - Wenn es ein Problem gibt, werden keine erneuten Versuche durchgeführt.

Ich suche eineTask<T> kompatibles Äquivalent zuLazy<T>(Func<T>, LazyThreadSafetyMode.PublicationOnly), d. h. es sollte sich wie angegeben verhalten: -

Alternativ zum Sperren In bestimmten Situationen möchten Sie möglicherweise den Overhead des Standard-Sperrverhaltens des Lazy-Objekts vermeiden. In seltenen Situationen kann es zu Deadlocks kommen. In solchen Fällen können Sie den Konstruktor Lazy (LazyThreadSafetyMode) oder Lazy (Func, LazyThreadSafetyMode) verwenden und LazyThreadSafetyMode.PublicationOnly angeben. Auf diese Weise kann das Lazy-Objekt eine Kopie des verzögert initialisierten Objekts in jedem von mehreren Threads erstellen, wenn die Threads gleichzeitig die Value-Eigenschaft aufrufen. Das Lazy-Objekt stellt sicher, dass alle Threads dieselbe Instanz des Lazy-initialisierten Objekts verwenden, und verwirft die nicht verwendeten Instanzen. Die Kosten für das Reduzieren des Sperren-Overheads bestehen daher darin, dass Ihr Programm manchmal zusätzliche Kopien eines teuren Objekts erstellt und verwirft. In den meisten Fällen ist dies unwahrscheinlich. Die Beispiele für die Konstruktoren Lazy (LazyThreadSafetyMode) und Lazy (Func, LazyThreadSafetyMode) veranschaulichen dieses Verhalten.

WICHTI

Wenn Sie PublicationOnly angeben, werden Ausnahmen nie zwischengespeichert, auch wenn Sie eine Factory-Methode angeben.

Gibt es eine FCL,Nito.AsyncEx oder ein ähnliches Konstrukt, das hier gut hineinpasst? Gelingt dies nicht, kann jemand eine elegante Möglichkeit finden, das Bit "Versuch in Bearbeitung" zu aktivieren (ich bin damit einverstanden, dass jeder Anrufer seinen eigenen Versuch auf die gleiche Weise unternimmt wie einLazy<T>( ...,(LazyThreadSafetyMode.PublicationOnly) hat) und doch noch das und die Cache-Verwaltung ordentlich gekapselt?

Antworten auf die Frage(8)

Ihre Antwort auf die Frage