c# - C# 编译器会优化变量吗?
问题描述
这是我的帖子的后续内容,这是并发可观察集合的正确实现吗?.
在那篇文章中,我有一个自定义类,它实现了一个通用的并发可观察列表,包括IEnumerable<T>.GetEnumerator()
. 这是原始代码:
public IEnumerator<T> GetEnumerator()
{
var localSnapshot = _snapshot; //create local variable to protect enumerator, if class member (_snapshot) should be changed/replaced while iterating
return ((IEnumerable<T>)localSnapshot).GetEnumerator();
}
_snapshot
是一个私有字段,只要实际内部集合 ( ) 被修改,就会Array
使用 a 重建。lock()
List<T> _list
但现在我认为该localSnapshot
变量根本不需要,代码应该是:
public IEnumerator<T> GetEnumerator()
{
return ((IEnumerable<T>)_snapshot).GetEnumerator();
}
因为localSnapshot
被简单地分配了对引用的相同地址的_snapshot
引用。GetEnumerator
不关心(也无法分辨)使用了哪个变量(当然,它会为自己使用创建另一个引用同一数组的变量)。
如果我的上述假设是正确的,我想知道编译器是否会将变量优化掉?然后生成的代码将是相同的。或者,如果不是:理论上复制引用是否可能是“有害的”,因为副本的更新程度将低于它可能的更新(另一个线程可以_snapshot
在复制完成后刷新,但在GetEnumerator
调用之前)?而且,编译器不优化代码的原因是“副作用”吗?因为优化是“无副作用”的?
解决方案
两个版本的代码在编译后会产生相同的结果。正如 TheGeneral 在评论中指出的那样,确保检查的一个好方法是查看sharplab.io。
请注意,仅当您在发布模式下编译时才适用。如果您在调试模式下编译,那么编译器将假定您可能需要中间变量来进行调试,并且不会对其进行优化。
理论上复制引用甚至可能是“有害的”,因为副本将比它可能的更新少(另一个线程可以在复制完成后刷新 _snapshot,但在调用 GetEnumerator 之前)
如果您在var localSnapshot = _snapshot;
和之间执行了一些代码,就会出现这种情况return ((IEnumerable<T>)localSnapshot).GetEnumerator()
。在那种情况下,优化是不可能的。否则,在这两种情况下,您都在读取值并直接使用它。两个版本的代码之间没有“新鲜度”的区别。
推荐阅读
- python - 使用 ValueError 绘制离散线图:视图限制最小值 0.0 小于 1,并且是无效的 Matplotlib 日期值
- c# - Visual Studio 以编程方式忽略调试器中的线程
- compiler-construction - 用 ocaml 编写的 C 编译器中的寄存器分配优化
- ansible - 使用 Ansible 精细管理系统用户
- jenkins - JenkinsFile 管道循环
- django - django模板标签html安全转义不适用于粗体
- reactjs - Flowtype:具有动态键类型注释的泛型类型
- phpunit - 如何使 phpunit @expectedException 与 hhvm 一起工作?
- c - 变量“x”在此处使用时未初始化
- c# - OnActionExecuting 未在引用的 MVC 项目中执行