C#非托管与托管下的数组性能测试

本文测试了托管和非托管两种情况下,对数据访问的性能差异。数组长度为10M,执行叠加操作(即 arr[i] = arr[i] + arr[i+1] ),执行100次求平均时间。

测试环境:

  • 使用机器为:AMD 3700X(8T16C), 16 GB DDR4 2400, 512GB NVME
  • 使用C#版本为4.7.2

注:StopWatch类是笔者自定义的计时工具,读者请使用一般计时方法替换。

public unsafe static void TestA()
{
	int count = 10_000_000;
	double[] ds = new double[count];
	var sws = StopWatch.Array(100);
	foreach (var sw in sws)
	{
		sw.Start("T1:Pointer");
		// 非托管代码
		unsafe
		{
			fixed (double* dp = ds)
			{
				for (int i = 0; i < count - 1; i++)
					dp[i] += dp[i + 1];
			}
		}
		
		// 托管代码
		sw.Start("T2:Managed");
		for (int i = 0; i < count - 1; i++)
			ds[i] += ds[i + 1];

		sw.StopAll(); 
	}

	StopWatch.Analyze(sws);
}

运行结果

通过以下结果可以看出,在运行次数少的情况下,非托管代码的性能较托管代码强5%。而在测试次数增加到500次以后,结果更加稳定。笔者还做了其他一些数组操作的测试,也基本符合出这个结果。所以可以得到结果,在测试次数少的情况下,非托管代码性能略微强于托管代码,但提升有限;而当测试次数达到一定次数,性能差别基本可以忽略。所以,即便是在性能要求特别苛刻的情况下也不建议使用,因为非托管代码性能提升非常有限,却带来了一定的安全性的隐患(毕竟非托管指针更不安全)。所以,非托管的代码更多的目的是为了与一些C/C++编写的类库进行调用,而不是为了性能提升。

# 100 次的运行结果
------------ Results.Median ------------
T1:Pointer: 19.0177 ms.
T2:Managed: 20.0183 ms.
------------ Results.Sum ------------
T1:Pointer: 1981.78 ms.
T2:Managed: 2040.88 ms.
------------ Results.Average ------------
T1:Pointer: 19.82 ms.
T2:Managed: 20.41 ms.

# 500次的运行结果
------------ Results.Median ------------
T1:Pointer: 20.0183 ms.
T2:Managed: 20.0185 ms.
------------ Results.Sum ------------
T1:Pointer: 10118.20 ms.
T2:Managed: 10266.31 ms.
------------ Results.Average ------------
T1:Pointer: 20.24 ms.
T2:Managed: 20.53 ms.
发布了334 篇原创文章 · 获赞 103 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/weixin_43145361/article/details/105063550