C# 我正在寻找一个懒惰的、线程安全的实现来缓存昂贵计算的第一个非空结果
我对使用singleton非常陌生,很难理解C#中singleton的惰性实现 假设我有一个最初为null/empty的字符串,当有人对该字符串执行get调用时,我必须仅在该字符串为null/empty时计算该字符串,否则返回现有字符串 我的正常实现如下所示C# 我正在寻找一个懒惰的、线程安全的实现来缓存昂贵计算的第一个非空结果,c#,thread-safety,singleton,C#,Thread Safety,Singleton,我对使用singleton非常陌生,很难理解C#中singleton的惰性实现 假设我有一个最初为null/empty的字符串,当有人对该字符串执行get调用时,我必须仅在该字符串为null/empty时计算该字符串,否则返回现有字符串 我的正常实现如下所示 public class A { private string str = null; public A() { } public string GetStr()
public class A
{
private string str = null;
public A()
{
}
public string GetStr()
{
if(String.IsNullOrEmpty(str))
{
str = CalculateStr();
}
return str;
}
}
如何实现上述示例的线程安全版本
编辑#1:calculatest()
可以返回空字符串。如果是这样的话,我们下次需要重新计算
编辑#2:用例是变量str应该是线程安全的,并且应该仅在其不为null/空时计算
编辑#3:我不知道它是否被称为singleton,我知道上面提供的示例不是线程安全的。对于昂贵调用的(确定性)结果的缓存,请使用-这有一个可选的LazyThreadSafetyMode
参数,允许您指定如何解决并发问题
更新-假设CalculateStr
不是静态的
请注意,以上两种情况都不需要单例实例-可以根据需要调用尽可能多的
a
实例,并且每个a
实例将(最终)缓存从CalculateStr
返回的单个非空值。如果需要单例,则共享a
实例,或使用IoC容器控制a的单例。首先,您的str应该是静态的,以成为“单例”。
其次,您可以在中使用Lazy
然后像这样定义singleton
private static readonly Lazy<string>
str =
new Lazy<string>
(() => CalculateStr());
私有静态只读延迟
str=
新懒汉
(()=>calculatest());
通过使用
Lazy
,您可以在不使用锁的情况下归档线程安全。现代C#in.NET内核中最简单的惰性单例实现如下:
public class A
{
public static readonly string LazyStr = CalculateStr();
private static string CalculateStr(){}
}
LazyStr
变量将仅在您第一次需要它时初始化(因为静态只读关键字),之后,它将始终保持不变
请尝试以下简单示例:
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Start at {DateTime.Now}");
Console.ReadKey();
Console.WriteLine(A.LazyString);
Console.ReadKey();
Console.WriteLine(A.LazyString);
Console.ReadKey();
}
}
public class A
{
public static readonly String LazyString = CalculateString();
private static string CalculateString()
{
return DateTime.Now.ToString();
}
}
你的问题是什么?这是一个怎样的单身汉?我假设这不是所有的代码;因此,
private A()
@JohnathanBarclay编辑了代码。我正在寻找一个懒惰的线程安全实现,我想这对您来说会很有趣:静态
不是必需的;无论如何只会有一个实例。我只是指出“singleton”应该与static一起工作,以确保程序中只有一个实例是的。我见过类似的例子,但是如何在字符串上添加像nullorempty这样的检查呢?谢谢,@starkkk92我没弄错吧:calculatest()
返回一个空字符串,我正在读那条评论,可能是这样的?如果是这样,您想在下一次调用GetStr
时重新计算它吗?是的,CalculateStr()可以返回null/empty,我们必须在下一次这种情况下重新计算。@starkkk92我们需要抛弃Lazy(不幸的是),以满足您的额外要求,即如果CalculateStr
的结果为null或空,则不缓存它。我已经更新了手动双重检查锁。谢谢。我继续使用双重检查锁定。虽然它是singleton的一个有效实现,但它并不懒惰,因为静态字段在第一次使用类之前初始化,并且LazyStr在您第一次需要时初始化的语句不是真的。如果它们是静态只读的,则不是。检查我发布的示例程序。字符串仅在您第一次调用它时初始化。您是否检查了程序的输入?只需在打印第一个日期之前延迟一段时间就可以看出差异。您可以看一看示例。为了给属性添加一些惰性程度,您应该添加静态构造函数,该构造函数强制不将type标记为beforefieldinit之前的,并且固有地禁止静态字段的早期初始化。请使用.NET core中C#7或更高版本的真实编译器进行尝试
public class A
{
public static readonly string LazyStr = CalculateStr();
private static string CalculateStr(){}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"Start at {DateTime.Now}");
Console.ReadKey();
Console.WriteLine(A.LazyString);
Console.ReadKey();
Console.WriteLine(A.LazyString);
Console.ReadKey();
}
}
public class A
{
public static readonly String LazyString = CalculateString();
private static string CalculateString()
{
return DateTime.Now.ToString();
}
}