【问题标题】:How Do I Prevent JIT Compiler From Optimising Out This Method如何防止 JIT 编译器优化此方法
【发布时间】:2011-02-24 22:17:11
【问题描述】:

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

//[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;
    }
}

我在使用 BinaryReader 解析文件时使用此方法来跳过空白字符块等。我发现当我这样称呼它时,JIT 编译器正在对其进行优化:

// Skip white space
this.reader.TakeWhile(IsWhiteSpace);//.FirstOrDefault();

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

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

【问题讨论】:

  • 只是好奇,您是如何确定它正在被优化的?

标签: c# .net optimization iterator jit


【解决方案1】:

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

您可能想阅读我关于迭代器块的文章(basicsimplementation details)和 Eric Lippert 的“心理调试”博文(part 1;part 2)。

请注意,调用 FirstOrDefault() 只会读取 first 字符。听起来您真的想消耗整个流直到条件失败 - 这意味着使用类似 Count() 的东西,它将遍历整个返回的序列。

或者——最好是 IMO——编写一个返回类型为 void 的“活动”方法来执行此操作。如果您对方法的返回值不感兴趣,这表明它可能不是一个理想的调用方法。 (并非总是如此,但通常如此。)

【讨论】:

  • 除了这个回复,我觉得我应该提到迭代器不是你想要的。您不是在空白区域上迭代,而是在忽略它,即这是命令意义上的函数调用
  • @Blindy:我只是在添加类似的东西:)
  • ugggh - 天哪,你是对的,我很傻 - 调用者需要从迭代器中提取值,因为它不会将它们推出。谢谢。 Lippert 的文章不错:)
  • 还有一个补充:在您的评论中,您说“Skip”,那么您为什么不像 Skip 方法一样命名和实现您的方法呢?
  • @Daniel:该方法本身实际上更像 LINQ 的“Take”方法。只有当您忽略返回的序列但重用相同的 BinaryReader 时,它才能被视为跳过:)
猜你喜欢
  • 1970-01-01
  • 2013-05-31
  • 1970-01-01
  • 1970-01-01
  • 2012-08-23
  • 2015-09-03
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多