syn*_*hko 4 .net c# multithreading .net-4.5
这更像是一个设计问题,而不是实际的错误或咆哮.我想知道人们对以下行为的看法:
在.NET中,当您想要有效地表示空IEnumerable时Enumerable.Empty<MyType>(),这将缓存空的可枚举实例.这是一个很好的免费微优化我认为如果依赖很多可能会有所帮助.
但是,这是实现的样子:
public static IEnumerable<TResult> Empty<TResult>() {
return EmptyEnumerable<TResult>.Instance;
}
internal class EmptyEnumerable<TElement>
{
static volatile TElement[] instance;
public static IEnumerable<TElement> Instance {
get {
if (instance == null) instance = new TElement[0];
return instance;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我希望在一次锁定之后,在另一次空检查之后发生赋值,但事实并非如此.
我想知道这是否是一个有意识的决定(即我们不关心可能创建几个对象,如果同时访问它们,我们将立即丢弃,因为我们宁愿避免锁定)或只是无知?
你会怎么做?
这是安全的,因为volatile序列对该字段的所有读取和写入.在读入之前,return instance;总是至少有一个写入设置该字段为有效值.
目前还不清楚将返回什么值,因为这里可能会创建多个数组.但总会有一个非空数组.
他们为什么这样做?好吧,锁具有更多的开销,volatile并且实现很容易实现.如果多个线程碰巧与此方法竞争,那么这些额外的实例将仅创建几次.对于每个赛程最多,将创建一个实例.初始化完成后,没有垃圾.
注意,没有volatile,实例字段可以在分配后翻转回零.这非常直观.没有任何同步,编译器可以像这样重写代码:
var instanceRead1 = instance;
var returnValue;
if (instanceRead1 == null) {
returnValue = new TElement[0];
instance = returnValue;
}
var instanceRead2 = instance;
if (instanceRead2 == returnValue) return instanceRead2;
else return null;
Run Code Online (Sandbox Code Playgroud)
在存在并发写入时,instanceRead2可以使用与刚写入的值不同的值.没有编译器会进行这样的重写,但它是合法的.CPU 可能会在某些体系结构上执行类似的操作.不太可能,但合法.也许有一个更合理的重写.
| 归档时间: |
|
| 查看次数: |
132 次 |
| 最近记录: |