lambda 中的初始化惰性字段未在多个线程之间重用

Initialized Lazy field in lambda not being reused among multiple threads

我有一个并行生成多个线程 (lambda) 的方法,在执行期间它访问 class 中定义的 Lazy 字段 属性,其中调用此方法的方式如下:

class A {

    private Lazy<FabricClient> _fabricClient => new Lazy<FabricClient>(() => GetDefaultFabricClient());

    private FabricClient FabricClient => _fabricClient.Value;

    internal A() 
    {
         Console.WriteLine(FabricClient.ToString());
    }


    private void tempMethod()
    {

        List<String> listOfStrings = GetStrings();

        RunThreads(listOfStrings.Select<string, ThreadStart>(tempString => () =>
        {

            var x = FabricClient.GetServiceList();

        }).ToArray());

    }

    private FabricClient GetDefaultFabricClient()
    {
      // Environment is inherited property, I cannot edit it  
      // And it's defined like
      //
      // public Environment Environment
      // { get { return _context.Environment; }}
      // 
      if (Environment.IsPublicEnvironment)
      {
            return new FabricClient(Credentials, Endpoint);
      } 

      return new FabricClient();
    }

}

是否有可能确保所有线程都将访问相同的 属性、相同的对象(因为目前每个线程都在初始化自己的 FabricClient Lazy 对象,而不是重复使用前一个被初始化的对象,可能不会使其成为静态对象) ?

在 tempMethod 执行之前也填充了惰性 FabricClient 属性,但它没有在 RunThreads 方法中重用。

这是错误的,Lazy默认是线程安全的

您可能需要在使用惰性对象的地方使用某种锁,因为所有这些线程都可能会重新初始化惰性对象,因为它们可能都在它完全创建之前调用它。

类似于:

lock(syncObject)
{
   var client = FabricClient;
}
var x = FabricClient.GetServiceList();

其中同步对象只是一个标准的新 clr 对象

object syncObject = new object();

您已将 _fabricClient 属性 定义为:

private Lazy<FabricClient> _fabricClient => new Lazy<FabricClient>(() => {
    return new FabricClient();
});

这(由于使用 =>)表示 "every time _fabricClient is accessed, create a new Lazy"。这与你想要的相反。

你想要一个普通字段,而不是 属性(你最好将其设置为只读):

private readonly Lazy<FabricClient> _fabricClient = new Lazy<FabricClient>(() => {
    return new FabricClient();
});

这将创建一个 Lazy 实例,并在构造 A 实例时将其存储在 _fabricClient 字段中。每次访问_fabricClient(通过FabricClient属性),都会得到相同的Lazy实例。


为了更清楚一点,您的 _fabricClient 属性 与:

private Lazy<FabricClient> _fabricClient
{
    get
    {
        return new Lazy<FabricClient>(() => {
            return new FabricClient();
        });
    }
}

你可以在这里添加一些日志记录,看到每次访问这个属性时都会执行getter:

private Lazy<FabricClient> _fabricClient
{
    get
    {
        Console.WriteLine("Constucting a new Lazy");
        return new Lazy<FabricClient>(() => {
            return new FabricClient();
        });
    }
}