我正在使用 Red Gate 的 Performance Profiler 优化一个物理模拟程序。处理碰撞检测的代码的一部分有大约 52 个以下小检查,处理 3 维 26 个方向的单元格,在两种情况下。
CollisionPrimitiveList cell = innerGrid[cellIndex + 1];
if (cell.Count > 0)
contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);
cell = innerGrid[cellIndex + grid.XExtent];
if (cell.Count > 0)
contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);
cell = innerGrid[cellIndex + grid.XzLayerSize];
if (cell.Count > 0)
contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);
作为程序的一个极其紧密的循环,所有这些都必须在同一个方法中,但我突然发现,在我将区域从二维扩展到三维之后(将计数增加到 52 个检查) 16),突然 cell.Count 不再被内联,即使它是一个简单的 getter。
public int Count { get { 返回计数; } }
这造成了巨大的性能损失,我花了相当长的时间才发现,当 cell.Count 在方法中出现 28 次或更少时,它每次都被内联,但是一旦 cell.Count 在方法中出现 29 次或更多,它一次都没有内联(即使绝大多数调用来自代码中很少执行的最坏情况部分。)
回到我的问题,有人知道如何绕过这个限制吗?我认为简单的解决方案就是将计数字段设置为内部而不是私有(private)的,但我想要一个比这更好的解决方案,或者至少只是更好地了解情况。我希望这种事情会在 Microsoft 的编写高性能托管应用程序页面上被提及,网址为 http://msdn.microsoft.com/en-us/library/ms973858.aspx但遗憾的是它不是(可能是因为 28 计数限制是多么随意?)
我正在使用 .NET 4.0。
编辑:看来我误解了我的小测试。我发现内联失败不是因为方法本身被调用了 28 次以上,而是因为按照某些标准,它们应该内联的方法“太长”了。这仍然让我感到困惑,因为我看不出如何合理地不内联一个简单的 getter(而且性能明显更好,正如我的探查器清楚地向我展示的那样),但显然 CLI JIT 编译器拒绝内联任何东西只是因为该方法已经很大(略有变化,我发现这个限制是代码大小(来自 idasm)为 1500,超过这个限制没有内联,即使在我的 getter 的情况下,一些测试显示没有添加额外的代码要内联的开销)。
谢谢。
最佳答案
我还没有对此进行测试,但似乎一种可能的解决方法是让多个属性都返回相同的东西。可以想象,您随后可以获得每个属性 28 个内联。
请注意,方法被内联的次数很可能取决于该方法的 native 代码的大小(参见 http://blogs.msdn.com/b/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx ),数字 28 特定于该属性。与更复杂的方法相比,简单的属性可能会被内联更多次。
关于c# - C# 28 次内联限制是否有解决方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5800957/