当您使用Lazy<T>的构造函数请求valueFactory和mode参数(我指的是这一个)时,可以指定LazyThreadSafetyMode.PublicationOnly。
通过这种方式,您可以防止缓存valueFactory引发的任何异常的延迟实例,但同时也失去了保证工厂函数只执行一次的能力。文档状态(粗体是我的):
当多个线程试图同时初始化一个Lazy实例时,所有线程都可以运行初始化方法(或者默认构造函数,如果没有初始化方法)。完成初始化的第一个线程设置Lazy实例的值。
有时这很好,有些时候最好避免这种情况,或者至少限制工厂函数的并发执行(假设有1000个线程同时执行数据库查询或调用web服务)。我通常使用SemaphoreSlim类实现这种受约束的并发。
我的问题很简单:
为了限制以SemaphoreSlim作为线程安全模式的Lazy<T>实例的工厂函数的并发执行,在使用LazyThreadSafetyMode.PublicationOnly (或类似机制)时是否存在任何问题或矛盾?
我看不出有什么问题,但我更喜欢问社区,因为我不是专家。
发布于 2019-07-23 20:35:07
因为没有标准方法来获得这样的行为,如果您真的需要它,那么无论如何,这是一种有效的方法。
甚至可能希望实现您自己的助手,以方便更容易地/更明确地使用此模式,无论是使用标准的Lazy,还是使用您自己定制的特殊LimitedConcurrencyNoErrorCachingLazy。
public class LimitedConcurrencyNoErrorCachingLazyFactory
{
    private Func<Int32, Int32, SemaphoreSlim> _createExternallyOwnedSemaphore;
    /// <param name="createExternallyOwnedSemaphore"> A factory to create externally owned(meaning that they are not owned/disposed by this instance) semaphore with specific initial and max count parameters.</param>
    public LimitedConcurrencyNoErrorCachingLazyFactory(Func<Int32, Int32, SemaphoreSlim> createExternallyOwnedSemaphore) 
    {
        this._createExternallyOwnedSemaphore =
            createExternallyOwnedSemaphore ??
            throw new ArgumentNullException(nameof(createExternallyOwnedSemaphore));
    }
    public Lazy<T> Create<T>(Func<T> valueFactory, Int32 maxConcurrency = 1)
    {
        if (valueFactory == null)
        {
            throw new ArgumentNullException(nameof(valueFactory));
        }
        if (maxConcurrency < 1)
        {
            throw new ArgumentOutOfRangeException(nameof(maxConcurrency));
        }
        var semaphore = this._createExternallyOwnedSemaphore(maxConcurrency, maxConcurrency);
        return new Lazy<T>(
            this.CreateLimitedConcurrencyValueFactory(semaphore, valueFactory), 
            LazyThreadSafetyMode.PublicationOnly);
    }
    public Func<T> CreateLimitedConcurrencyValueFactory(SemaphoreSlim semaphore, Func<T> valueFactory)
    {
        return () =>
        {
            semaphore.Wait();
            try 
            {
                return valueFactory();
            }
            finally
            {
                semaphore.Release();
            }
        }
    }
}唯一稍微偏离的是,对于上述线程,将并发限制在多个线程上。
假设有1000个线程同时执行数据库查询或调用web服务。
似乎不太有用
Lazy.Value的作业/会话使用一些重试策略,即使其中某些部分可能已经成功。因此,也许,更简单的单螺纹方法是一个更好的选择。
https://softwareengineering.stackexchange.com/questions/395078
复制相似问题