首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用Lazy<T>实例化Lazy<T>的工厂函数

用Lazy<T>实例化Lazy<T>的工厂函数
EN

Software Engineering用户
提问于 2019-07-23 10:59:44
回答 1查看 504关注 0票数 1

当您使用Lazy<T>的构造函数请求valueFactorymode参数(我指的是这一个)时,可以指定LazyThreadSafetyMode.PublicationOnly

通过这种方式,您可以防止缓存valueFactory引发的任何异常的延迟实例,但同时也失去了保证工厂函数只执行一次的能力。文档状态(粗体是我的):

当多个线程试图同时初始化一个Lazy实例时,所有线程都可以运行初始化方法(或者默认构造函数,如果没有初始化方法)。完成初始化的第一个线程设置Lazy实例的值。

有时这很好,有些时候最好避免这种情况,或者至少限制工厂函数的并发执行(假设有1000个线程同时执行数据库查询或调用web服务)。我通常使用SemaphoreSlim类实现这种受约束的并发。

我的问题很简单:

为了限制以SemaphoreSlim作为线程安全模式的Lazy<T>实例的工厂函数的并发执行,在使用LazyThreadSafetyMode.PublicationOnly (或类似机制)时是否存在任何问题或矛盾?

我看不出有什么问题,但我更喜欢问社区,因为我不是专家。

EN

回答 1

Software Engineering用户

回答已采纳

发布于 2019-07-23 20:35:07

因为没有标准方法来获得这样的行为,如果您真的需要它,那么无论如何,这是一种有效的方法。

甚至可能希望实现您自己的助手,以方便更容易地/更明确地使用此模式,无论是使用标准的Lazy,还是使用您自己定制的特殊LimitedConcurrencyNoErrorCachingLazy

代码语言:javascript
运行
复制
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服务。

似乎不太有用

  1. 只是使用那些代价高昂的并行调用来增加外部服务的负载。
  2. 您的应用程序的可靠性只增加了一小部分,而且基本上是意想不到的。
    • 由于您仍然需要对未能检索Lazy.Value的作业/会话使用一些重试策略,即使其中某些部分可能已经成功。

因此,也许,更简单的单螺纹方法是一个更好的选择。

票数 2
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/395078

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档