将浮点数数组封送到结构数组而不复制
本文关键字:数组 结构 复制 浮点数 | 更新日期: 2023-09-27 18:32:50
假设我有以下代码
public static class Main
{
public struct Vec3
{
public float x, y, z;
}
public void Entry()
{
float[9] floats = new floats[9] { 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f };
Vec3[3] vecs;
}
}
我想将浮点数[]转换为Vec3[]。
有没有办法通过封送处理来做到这一点,这样所需的复制比迭代 float[] 并将每个浮点数复制到 Vec3[] 更快?假设 float[] 非常大。
您可以使用
System.Runtime.InteropServices.Marshal
类来执行此操作:
unsafe
{
fixed (Vec3* vecsPointer = vecs)
{
Marshal.Copy(floats, 0, new IntPtr(vecsPointer), floats.Length);
}
}
也就是说,我认为如果可能的话,通常最好避免unsafe
,即使存在一些可衡量的性能差异。对我来说,选择上述副本而不是直接托管副本(在发布版本中可能非常快,尽管可能不如上述速度快(必须是一个相当显着的性能改进。
当然,您应该仔细衡量每种方法的整体影响,并确保在采用unsafe
方法之前值得潜在的维护麻烦。
编辑:出于好奇,我继续做了一个简单的测试。我创建了一个大小为 1MB 的float[]
并复制到Vec3[]
.我使用了上面的内容,并将其与一个简单的循环进行了比较,如下所示:
for (int k = 0, l = 0; k + 2 < floats.Length; k += 3, l++)
{
vecs[l].x = floats[k];
vecs[l].y = floats[k + 1];
vecs[l].z = floats[k + 2];
}
在我的测试中,我每次试用每个副本执行 10,000 次,副本的总大小约为 10GB。
unsafe
版本"仅"比安全版本快约(仅慢于(2倍。每10,000份试用大约需要1.5秒unsafe
,安全需要3秒。2 倍的加速听起来不错,但当然,只有当你的程序不做其他事情时,你才能得到它。在现实世界的计划中,这可能转化为 5% 或更少的改进,具体取决于其他情况。
我看到的其他一些有趣的事情:
- 使用 Marshal.Copy((,复制 2 的精确幂比其他东西要快得多。 例如,2^20 字节与其他字节。在这种情况下,它接近 3 倍的加速。
- 与上述相关,Marshal.Copy(( 似乎对副本的确切大小更加敏感。使用安全代码可以获得更一致的性能,当然速度较慢。
- 在足够小的缓冲区大小(似乎大约 100-200 字节(下,
unsafe
代码的设置开销会阻碍它,并且它与安全版本一样慢。