C# 优化和副作用
C# 编译器或 JITter 完成的优化是否会产生明显的副作用?
我有一个例子。
var x = new Something();
A(x);
B(x);
当调用 A(x)
时,x
保证在 A
结束时保持活动状态 - 因为 B
使用相同的参数。但是,如果 B
定义为
public void B(Something x) { }
那么优化器可以消除 B(x)
,然后 GC.KeepAlive(x)
调用可能会是必要的。
这种优化真的可以通过JITter来完成吗?
除了堆栈跟踪更改之外,是否还有其他优化可能会产生明显的副作用?
Can optimizations done by the C# compiler or the JITter have visible side effects?
One example I've though off.
var x = new Something();
A(x);
B(x);
When calling A(x)
x
is guaranteed to be kept alive to the end of A
- because B
uses the same parameter. But if B
is defined as
public void B(Something x) { }
Then the B(x)
can be eliminated by the optimizer and then a GC.KeepAlive(x)
call might be necessary instead.
Can this optimization actually be done by the JITter?
Are there other optimizations that might have visible side effects, except stack trace changes?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您的函数 B 不使用参数 x,那么消除它并尽早收集 x 不会产生任何明显的副作用。
要成为“可见的副作用”,它们必须对程序可见,而不是对调试器或对象查看器等外部工具可见。
If your function B does not use the parameter x, then eliminating it and collecting x early does not have any visible side effects.
To be "visible side effects", they have to be visible to the program, not to an external tool like a debugger or object viewer.
这种说法是错误的。假设方法 A 总是抛出异常。抖动可以知道永远不会到达B,因此可以立即释放x。假设方法 A 在最后一次引用 x 之后进入无条件无限循环;同样,抖动可以通过静态分析知道 x 永远不会再次被引用,并安排对其进行清理。我不知道抖动是否真正执行了这些优化;它们看起来很狡猾,但它们是合法的。
是的,在实践中,它已经完成了。这不是可观察到的副作用。
规范第 3.9 节证明了这一点,为了您的方便,我引用了该节:
您的问题在规范的第 3.10 节中得到了解答,为了您的方便,我在此引用该部分:
倒数第二段我相信是您最关心的一段;也就是说,运行时允许执行哪些优化来影响可观察到的副作用?允许运行时执行不影响可观察到的副作用的任何优化。
请注意,特别是数据依赖性仅保留在执行线程内。从另一个执行线程观察时,不保证保留数据依赖性。
如果这不能回答您的问题,请提出更具体的问题。特别是,如果您不认为上面给出的定义与您对“可观察到的副作用”的定义不匹配,则需要对“可观察到的副作用”进行仔细和精确的定义,以便更详细地回答您的问题。
This statement is false. Suppose method A always throws an exception. The jitter could know that B will never be reached, and therefore x can be released immediately. Suppose method A goes into an unconditional infinite loop after its last reference to x; again, the jitter could know that via static analysis, determine that x will never be referenced again, and schedule it to be cleaned up. I do not know if the jitter actually performs these optimization; they seem dodgy, but they are legal.
Yes, and in practice, it is done. That is not an observable side effect.
This is justified by section 3.9 of the specification, which I quote for your convenience:
Your question is answered in section 3.10 of the specification, which I quote here for your convenience:
The second-to-last paragraph is I believe the one you are most concerned about; that is, what optimizations is the runtime allowed to perform with respect to affecting observable side effects? The runtime is permitted to perform any optimization which does not affect an observable side effect.
Note that in particular data dependence is only preserved within a thread of execution. Data dependence is not guaranteed to be preserved when observed from another thread of execution.
If that doesn't answer your question, ask a more specific question. In particular, a careful and precise definition of "observable side effect" will be necessary to answer your question in more detail, if you do not consider the definition given above to match your definition of "observable side effect".
在您的问题中包含
B
只会让事情变得混乱。给定以下代码:假设
A(x)
是托管代码,则调用A(x)
维护对x
的引用,因此垃圾在A
返回之前,收集器无法收集x
。或者至少直到A
不再需要它。 JITer 完成的优化(不存在错误)不会过早收集x
。您应该定义“可见副作用”的含义。人们希望 JITer 优化至少能产生使代码更小或更快的副作用。这些是“可见的”吗?或者你的意思是“不受欢迎的”?
Including
B
in your question just confuses the matter. Given this code:Assuming that
A(x)
is managed code, then callingA(x)
maintains a reference tox
, so the garbage collector can't collectx
until afterA
returns. Or at least untilA
no longer needs it. The optimizations done by the JITer (absent bugs) will not prematurely collectx
.You should define what you mean by "visible side effects." One would hope that JITer optimizations at least have the side effect of making your code smaller or faster. Are those "visible?" Or do you mean "undesireable?"
Eric Lippert 开始了一个关于重构的精彩系列,这让我相信 C# 编译器和 JITter 确保不会引入副作用。 第 1 部分< /a> 和 第 2 部分 目前已上线。
Eric Lippert has started a great series about refactoring which leads me to believe that the C# Compiler and JITter makes sure not to introduce side effects. Part 1 and Part 2 are currently online.