Jen*_*nsB 2 c# multithreading .net-core asp.net-core
我有一个属性定义为:
private static MyStaticCache? _myStaticCache;
Run Code Online (Sandbox Code Playgroud)
MyStaticCache
是一个具有字符串属性的类。多个线程可以访问_myStaticCache
。如果该属性为 null 或该值是旧的,则任何访问该属性的线程都会从源获取该值并将其设置_myStaticCache
为该值。
public string GetValue()
{
if (_myStaticCache == null || _myStaticCache.CacheIsStale())
_myStaticCache = GetValueFromSource();
return _myStaticCache.Value1;
}
Run Code Online (Sandbox Code Playgroud)
没有代码可以或不会设置_myStaticCache
回 null。
人们很快就会发现,可以多次调用GetValueFromSource()
和分配_myStaticCache
人们很快就会发现,如果多个线程在第一次分配之前或已经过时时运行,则
我的问题是这样的。有没有办法这会导致崩溃?的分配是_myStaticCache
原子的,还是可以在写入过程中进行读取?
源方法可以并行调用 N 次这一事实并不重要。缓存的超时时间为 30 天,多个线程不太可能同时运行,尽管并非不可能,而且即使有 100 个线程并行运行调用它,该方法也会为每个线程返回相同的值并且能够毫无问题地处理负载。
现在我可以使用互斥体,或者将读取和写入包装起来lock()
,但我认为这会在调用该方法的 99.999% 的时间里阻碍性能,同样,它只会每 30 天为空或旧一次。
只要MyStaticCache
是 a class
(或接口;基本上:引用类型),就应该没问题。
语言规范保证您永远不会出现引用被破坏的情况,所以它不应该崩溃:
12.5 变量引用的原子性
以下数据类型的读取和写入应是原子的:
bool
、char
、byte
、sbyte
、short
、ushort
、uint
、int
、float
和引用类型。此外,对前面列表中的基础类型的枚举类型的读取和写入也应该是原子的。其他类型(包括long
、ulong
、double
和 )decimal
以及用户定义类型的读取和写入不需要是原子的。除了为此目的而设计的库函数之外,不保证原子读取-修改-写入,例如在递增或递减的情况下。
因此,只要您不担心针对初始/陈旧值多次运行慢速路径,或者与寄存器使用等相关的问题:您应该没问题。
就我个人而言,我可能会CacheIsStale()
在计时器中进行检查(以您选择的频率),将字段设置为null
检测到过时的时间,而不是不断检查两个条件。您甚至可以在计时器回调内部进行刷新,并将静态字段设置为新引用,因此:
public string GetValue()
=> (_myStaticCache ?? FetchAndAssign()).Value1;
private MyStaticCache FetchAndAssign()
=> _myStaticCache = GetValueFromSource();
private void TimerCallback()
{
if (_myStaticCache is null || _myStaticCache.CacheIsStale())
FetchAndAssign();
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们只能评论_myStaticCache
; .Value1
做什么取决于您的代码,并且可能是也可能不是线程安全的。
归档时间: |
|
查看次数: |
747 次 |
最近记录: |