如何防止JIT编译器优化此方法

Xca*_*bur 3 .net c# optimization jit iterator

我有一个扩展方法,如下所示:

//[MethodImpl(MethodImplOptions.NoOptimization)]
public static IEnumerable<char> TakeWhile(this BinaryReader reader, Func<int, bool> condition)
{
    while (condition(reader.PeekChar()))
    {
        char c = reader.ReadChar();
        yield return c;
    }
}
Run Code Online (Sandbox Code Playgroud)

在使用BinaryReader解析文件时,我使用此方法来跳过空白字符块,以及其他内容.我发现JIT编译器正在优化它,当我这样调用它时:

// Skip white space
this.reader.TakeWhile(IsWhiteSpace);//.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

我已经尝试添加[MethodImpl(...)]属性来指示JIT编译器不优化方法,但它不起作用.现在显然我可以编写另一个实现这个操作底层流缓冲区位置的实现但出于好奇我想知道为什么会这样.

我发现阻止优化的唯一方法是使用IEnumerable结果(例如 - 通过调用上面评论的.FirstOrDefault())或将代码复制到调用方法中.我已经尝试使用MethodImplAttribute阻止调用方法的优化,但这不起作用.奇怪的是,优化在Debug构建下完全关闭,所以它不应该在任何情况下发生.有谁知道另一种阻止优化的方法?

Jon*_*eet 8

不,JIT 没有优化它.但是,您的代码都不会被执行 - 因为您忽略了返回的值.在第一次调用之前MoveNext(),迭代器块中的代码都不会运行.这与JIT无关,而且与迭代器块的工作方式有关.

您可能想阅读关于迭代器块(基础知识,实现细节)和Eric Lippert的"心理调试"博客文章(第1 部分 ; 第2部分)的文章.

请注意,调用FirstOrDefault()只会读取第一个字符.听起来你真的想要消耗整个流,直到条件失败 - 这意味着使用类似的东西Count()将迭代整个返回的序列.

或者 - 并且最好是IMO - 使用void返回类型编写"活动"方法来执行此操作.如果你对一个方法的返回值不感兴趣,那就是一个信号,它可能不是一个理想的调用方法.(情况并非总是这样,但通常是这样.)