如何避免 TRY 语句导致程序性能不佳?
How can I avoid poor program performance from a TRY statement?
我目前正在开发一个基本的体素(长方体)游戏引擎,但遇到了性能问题。游戏每一帧:
找到玩家的观察方向 → 检查玩家直接观察路径中的每个坐标 → 找到最近的占用 space → 在这个方块周围画一个线框。
我正在使用 OpenTK,OpenGL 的绑定。NET/Mono(特别是 C#)。我的代码 OnRenderFrame 包含这个:
try
{
for (int i = 0; i < 8; i++)
{
Vector3 block = InterfaceUtils.FindBlockLoc(Utilities.RoundToInt(cam.Position + (cam.lookat * i)));
if (block != Vector3.Zero)
{
// Draw the wireframe
}
}
}
catch
{
}
这段代码的目的是检查玩家最多八个方块,直到找到一个方块。唯一的问题是 try 语句最常抛出(已处理的)异常:但由此造成的延迟是巨大的。当我查看 space 时,我只得到 11FPS,但如果代码成功,我得到 50。
如果代码成功(可以绘制线框),我得到:
块查找通过检查该位置的块的对象列表来工作。
public static Vector3 FindBlockLoc(Vector3 location)
{
Vector3 result = new Vector3(Vector3.Zero);
result = Deltashot.Game.objects.Find(v => v.Position == location).Position;
if (result != null)
{
return result;
}
else
{
return Vector3.Zero;
}
}
但是,这个 returns 是一个 NullReferenceException,我不得不使用 TRY 语句将其设置为 运行。这又回到了原点...
Throwing and catching Exceptions is a costly operation in C#, and it seems you are using exceptions as flow control.
你应该避免 NullReferenceException
而不是在它发生时抓住它。
我猜异常发生在这里:
result = Deltashot.Game.objects.Find(v => v.Position == location).Position;
我建议这样:
public static Vector3 FindBlockLoc(Vector3 location)
{
var result = Deltashot.Game.objects.Find(v => v.Position == location);
if (result != null && result.Position != null)
{
return result.Position;
}
else
{
return Vector3.Zero;
}
}
如果你改变这一行
result = Deltashot.Game.objects.Find(v => v.Position == location).Position;
对此:
result = Deltashot.Game.objects.Find(v => v.Position == location);
if (result != null)
{
return result.Position;
}
...
如果 Find
方法 returns 为 null,并且您尝试从 null 结果访问任何成员,您可能会阻止该异常,您会得到一个 null 引用异常 - 您应该与其用 try/catch 包装一些东西,不如花点时间弄清楚为什么会出现异常。
一个简单的方法是用检查点分解所有代码(直到你找出错误发生的地方)因为也有可能 Deltashot.Game
为空或 Deltashot.Game.objects
为空。
我通过将函数更改为:
解决了这个问题
public static Volume FindBlock(Vector3 location)
{
return Deltashot.Game.objects.Find(v => v.Position == location);
}
所以我返回了整个 Volume 对象(而不仅仅是位置)。然后我将调用它的代码更改为:
for (int i = 0; i < 8; i++)
{
var block = InterfaceUtils.FindBlock(Utilities.RoundToInt(cam.Position + (cam.lookat * i)));
if (block != null)
{
// Draw the wireframe
}
}
因此该块最初是无类型的,并将其与 var 的 null 定义(不会抛出异常!)进行比较
感谢 Juliano 的(类似)解决方案和 tophallen 的诊断建议。
我目前正在开发一个基本的体素(长方体)游戏引擎,但遇到了性能问题。游戏每一帧:
找到玩家的观察方向 → 检查玩家直接观察路径中的每个坐标 → 找到最近的占用 space → 在这个方块周围画一个线框。
我正在使用 OpenTK,OpenGL 的绑定。NET/Mono(特别是 C#)。我的代码 OnRenderFrame 包含这个:
try
{
for (int i = 0; i < 8; i++)
{
Vector3 block = InterfaceUtils.FindBlockLoc(Utilities.RoundToInt(cam.Position + (cam.lookat * i)));
if (block != Vector3.Zero)
{
// Draw the wireframe
}
}
}
catch
{
}
这段代码的目的是检查玩家最多八个方块,直到找到一个方块。唯一的问题是 try 语句最常抛出(已处理的)异常:但由此造成的延迟是巨大的。当我查看 space 时,我只得到 11FPS,但如果代码成功,我得到 50。
如果代码成功(可以绘制线框),我得到:
块查找通过检查该位置的块的对象列表来工作。
public static Vector3 FindBlockLoc(Vector3 location)
{
Vector3 result = new Vector3(Vector3.Zero);
result = Deltashot.Game.objects.Find(v => v.Position == location).Position;
if (result != null)
{
return result;
}
else
{
return Vector3.Zero;
}
}
但是,这个 returns 是一个 NullReferenceException,我不得不使用 TRY 语句将其设置为 运行。这又回到了原点...
Throwing and catching Exceptions is a costly operation in C#, and it seems you are using exceptions as flow control.
你应该避免 NullReferenceException
而不是在它发生时抓住它。
我猜异常发生在这里:
result = Deltashot.Game.objects.Find(v => v.Position == location).Position;
我建议这样:
public static Vector3 FindBlockLoc(Vector3 location)
{
var result = Deltashot.Game.objects.Find(v => v.Position == location);
if (result != null && result.Position != null)
{
return result.Position;
}
else
{
return Vector3.Zero;
}
}
如果你改变这一行
result = Deltashot.Game.objects.Find(v => v.Position == location).Position;
对此:
result = Deltashot.Game.objects.Find(v => v.Position == location);
if (result != null)
{
return result.Position;
}
...
如果 Find
方法 returns 为 null,并且您尝试从 null 结果访问任何成员,您可能会阻止该异常,您会得到一个 null 引用异常 - 您应该与其用 try/catch 包装一些东西,不如花点时间弄清楚为什么会出现异常。
一个简单的方法是用检查点分解所有代码(直到你找出错误发生的地方)因为也有可能 Deltashot.Game
为空或 Deltashot.Game.objects
为空。
我通过将函数更改为:
解决了这个问题public static Volume FindBlock(Vector3 location)
{
return Deltashot.Game.objects.Find(v => v.Position == location);
}
所以我返回了整个 Volume 对象(而不仅仅是位置)。然后我将调用它的代码更改为:
for (int i = 0; i < 8; i++)
{
var block = InterfaceUtils.FindBlock(Utilities.RoundToInt(cam.Position + (cam.lookat * i)));
if (block != null)
{
// Draw the wireframe
}
}
因此该块最初是无类型的,并将其与 var 的 null 定义(不会抛出异常!)进行比较
感谢 Juliano 的(类似)解决方案和 tophallen 的诊断建议。