【发布时间】:2021-05-25 17:58:22
【问题描述】:
在 Unity 中,我注意到与 Kotlin 中的类似实现相比,我在某些代码逻辑中的性能低于标准。分析后,我怀疑语言/运行时本身可能会以某种方式变慢。因此,我在 Kotlin 和 C# 中都做了一个非常简短的基准测试来衡量基本操作的性能:
kotlin部分如下。请注意,Matrix4 和 Vector3 是 libGDX(Java/Kotlin 的游戏库)类,它们只不过是数据的容器。 mul 函数将矩阵与向量相乘,并将结果原位存储回向量中。
fun benchmark(a: Matrix4, b: List<Vector3>) {
var i = 0;
while (i < 100000) {
b[i].mul(a);
++i;
}
}
var a = Matrix4(floatArrayOf(1f, 2f, 3f, 4f, 3f, 2f, 1f, 2f, 3f, 4f, 3f, 2f, 1f, 2f, 3f, 4f))
var b = List<Vector3>();
for (i in 0..100000) {
b.add(Vector3(3f, 2f, 1f));
}
// warmup JIT
for (i in 0..9) {
benchmark(a, b)
}
var t: Double = 0.0;
for (i in 0..9) {
t += measureNanoTime {
benchmark(a, b)
}.toDouble()
}
println(t / 10.0 / 1000000.0) // milliseconds
Unity C#部分如下。请注意,M4 和 V3 是为匹配 libGDX 所创建的辅助类。
private void Benchmark(M4 a, List<V3> b)
{
var i = 0;
while (i < 100000)
{
b[i].mul(a);
++i;
}
}
var a = new M4(1f, 2f, 3f, 4f, 3f, 2f, 1f, 2f, 3f, 4f, 3f, 2f, 1f, 2f, 3f, 4f);
var b = new List<V3>();
for (int i = 0; i < 100000; ++i)
{
b.Add(new V3(3, 2, 1));
}
// warmup JIT
for (int i = 0; i < 10; ++i)
{
Benchmark(a, b);
}
var t = 0.0;
for (int i = 0; i < 10; ++i)
{
var s = (double) nanoTime();
Benchmark(a, b);
var e = (double) nanoTime();
t += e - s;
}
Debug.Log(t / 10.0 / 1000000.0); // milliseconds
mul 的实现与 libGDX 的精确实现 (https://github.com/libgdx/libgdx/bl...x/src/com/badlogic/gdx/math/Vector3.java#L353) 相匹配。
该设备是 2015 年中的 MacBook Pro。 Unity 版本是 2020.3.0f1,使用 Mono 后端构建到 OSX 独立版本,而不是开发版本。
结果如下:
- Kotlin:0.3658762ms
- Unity C#:1.74067 毫秒(几乎慢了 4 倍)。如果我将
M4和V3更改为结构而不是类,它会变得更慢:2.51 毫秒(几乎慢了 6 倍)。
造成如此显着差异的原因是什么?
【问题讨论】:
-
这两个实现不一样。并且使用双精度数来计算时间是不安全的,并且会受到缩放和舍入问题的影响。请改用
Stopwatch。 -
SIMD CPU 指令和使用它们的类型(如 Vector3)的重要性怎么强调都不为过。自 2000 年代以来的所有 CPU 都可以一次处理多个浮点数/整数/双精度数。他们还优化了 3D 转换,由 4x4 矩阵乘法执行。 Vector3 和 Matrix4x4 不仅仅是为了方便。他们的很多操作实际上都是使用 SIMD 指令进行的
-
@PanagiotisKanavos 我使用stackoverflow.com/a/44136515/3308553 找到
nanoTime,它在下面使用Stopwatch。此外,从 libGDX 的源代码 (github.com/libgdx/libgdx/bl...x/src/com/badlogic/gdx/math/…) 来看,他们的类似乎没有为我在基准测试中调用的特定函数明确使用 SIMD。 -
如果你需要做很多向量和其他数学运算,不如使用 Unity 的 JobSystem 和 Burst Compiler!
标签: java c# performance unity3d kotlin