C# 中的计算开销 - 使用 getter/setter 与使用 getter/setter直接修改数组和施法速度

StackOverflow https://stackoverflow.com/questions/3018536

本来想写一篇长篇大论的,不过我还是把它总结一下吧:

我正在尝试通过 XNA 模拟 NES 的图形老式风格。然而,我的 FPS 很慢,试图修改每帧 65K 像素。如果我只是循环遍历所有 65K 像素并将它们设置为任意颜色,我会得到 64FPS。我编写的用于查找应将什么颜色放置在何处的代码,我得到了 1FPS。

我认为这是因为我的面向对象的代码。

现在,我将事物分为大约六个类,并带有 getter/setter。我猜想每帧至少调用 360K getter,我认为这是很大的开销。每个类都包含 1D 或 2D 数组,其中包含自定义枚举、int、Color 或 Vector2D、字节。

如果我将所有类合并为一个类,并直接访问每个数组的内容会怎么样?代码看起来会很乱,并且抛弃了面向对象编码的概念,但速度可能会快得多。

我也不担心访问冲突,因为任何获取/设置数组中数据的尝试都将在块中完成。例如,所有对数组的写入都将在从数组访问任何数据之前进行。


至于铸造,我说过我正在使用 自定义枚举、int、Color 和 Vector2D、bytes。 哪些数据类型在 .net Framework、XNA、XBox、C# 中使用和访问速度最快?我认为不断的铸造可能是这里速度减慢的一个原因。

另外,我没有使用数学来确定数据应该放置在哪些索引中,而是使用了预先计算的查找表,因此我不必使用每帧的常量乘法、加法、减法、除法。:)

有帮助吗?

解决方案

如果您是 XNA 开发人员,GDC 2008 上有一个精彩的演示值得一读。它被称为 了解 XNA 框架性能.

对于您当前的架构 - 您还没有真正充分地描述它以给出明确的答案 - 您可能在紧密的循环中做了太多不必要的“东西”。如果我不得不猜测,我建议您当前的方法正在破坏缓存 - 您需要修复数据布局。

在理想的情况下,你应该有一个尽可能小的大数组 值类型 (结构而不是类),以及将数据线性推入其中的大量内联循环。

(在旁边:关于什么是快:整数和浮点数学运算非常快 - 一般来说,您不应该使用查找表。函数调用非常快 - 以至于在传递大型结构时复制它们将更加重要。JIT 将内联简单的 getter 和 setter - 尽管您不应该依赖它在非常紧密的循环中内联任何其他内容 - 比如您的 bitter。)

然而 - 即使优化 - 你当前的架构很糟糕。你所做的事情与现代 GPU 的工作方式背道而驰。您应该将精灵加载到 GPU 上并让它合成您的场景。

如果您想在像素级别操作精灵(例如:正如您所提到的托盘交换)那么您应该使用像素着色器。360(和 PC)上的 CPU 很快,但是当你做这样的事情时,GPU 的速度要快得多!

精灵效果 XNA 示例是一个很好的起点。

其他提示

您是否对代码进行了分析以确定速度变慢的位置?在重写应用程序之前,您至少应该知道哪些部分需要重写。

我强烈怀疑访问器和数据转换的开销是微不足道的。更有可能的是,您的算法正在执行不必要的工作,重新计算它们可以缓存的值,以及可以在不破坏对象设计的情况下解决的其他问题。

您是否为每个像素指定颜色等?如果是这样的话,我认为你真的应该更多地考虑一下架构。开始使用精灵来加快速度。

编辑

好吧,我认为您的解决方案可以加载多个具有不同颜色的精灵(几个像素的精灵)并重用它们。指向相同的精灵比为每个像素分配不同的颜色更快,因为精灵已经加载到内存中

与任何性能问题一样,您应该分析应用程序以识别瓶颈,而不是试图猜测。我严重怀疑 getter 和 setter 是问题的根源。编译器几乎总是内联这些类型的函数。我也很好奇你对数学有什么看法。例如,将两个整数相乘是计算机可以做的最快的事情之一。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top