кэширование результата от фабричного метода [n async], если он не генерирует

ОБНОВЛЕНИЕ: Сильно исправленный после того, как @usr указал, что я неправильно предположилLazy<T>режим безопасности потока по умолчанию былLazyThreadSafetyMode.PublicationOnly...

Я хочу лениво вычислить значение черезasync Фабричный метод (т.е. он возвращаетTask<T>) и кешировать на успех. В порядке исключения я хочу, чтобы это было доступно для меня. Я, однако, не хочу стать жертвойповедение при кэшировании исключений тотLazy<T> в режиме по умолчанию (LazyThreadSafetyMode.ExecutionAndPublication)

Кэширование исключений: когда вы используете фабричные методы, исключения кэшируются. То есть, если метод фабрики выдает исключение в первый раз, когда поток пытается получить доступ к свойству Value объекта Lazy, то же исключение выдается при каждой последующей попытке. Это гарантирует, что каждый вызов свойства Value приводит к одному и тому же результату, и позволяет избежать незначительных ошибок, которые могут возникнуть, если разные потоки получают разные результаты. Ленивый заменяет фактический T, который в противном случае был бы инициализирован в более ранней точке, обычно во время запуска. Отказ в этой более ранней точке обычно фатален. Если существует вероятность восстанавливаемого сбоя, мы рекомендуем встроить логику повтора в процедуру инициализации (в данном случае, в метод фабрики), как если бы вы не использовали отложенную инициализацию.

Стивен Туб имеетAsyncLazy класс и рецензия это кажется правильным:

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(); }
}

Однако это фактически то же поведение, что и по умолчаниюLazy<T> - если есть проблема, повторных попыток не будет.

Я ищуTask<T> совместимый эквивалентLazy<T>(Func<T>, LazyThreadSafetyMode.PublicationOnly)то есть он должен вести себя так, как указано:

Альтернатива блокировке В некоторых ситуациях вы можете избежать издержек, связанных с поведением блокировки объекта Lazy по умолчанию. В редких ситуациях возможны тупики. В таких случаях вы можете использовать конструктор Lazy (LazyThreadSafetyMode) или Lazy (Func, LazyThreadSafetyMode) и указать LazyThreadSafetyMode.PublicationOnly. Это позволяет объекту Lazy создавать копию лениво инициализированного объекта в каждом из нескольких потоков, если потоки одновременно вызывают свойство Value. Объект Lazy гарантирует, что все потоки используют один и тот же экземпляр лениво инициализированного объекта, и отбрасывает неиспользуемые экземпляры. Таким образом, стоимость сокращения накладных расходов на блокировку заключается в том, что ваша программа может иногда создавать и отбрасывать дополнительные копии дорогостоящего объекта. В большинстве случаев это маловероятно. Примеры для конструкторов Lazy (LazyThreadSafetyMode) и Lazy (Func, LazyThreadSafetyMode) демонстрируют это поведение.

ВАЖНЫЙ

Когда вы указываете PublicationOnly, исключения никогда не кэшируются, даже если вы указали фабричный метод.

Есть ли FCL,Nito.AsyncEx или подобная конструкция, которая могла бы хорошо здесь вписаться? Если это не удастся, может кто-нибудь увидеть элегантный способ скрыть бит «попытка в процессе» (я в порядке, когда каждый вызывающий абонент делает свою собственную попытку так же, какLazy<T>( ...,(LazyThreadSafetyMode.PublicationOnly) делает) и все же все еще есть это, и управление кешем инкапсулировано аккуратно?

Ответы на вопрос(4)

Ваш ответ на вопрос