真正不安全的代码性能
我知道不安全的代码更适合访问像Windows API之类的东西,并执行不安全的类型转换,而不是编写更高性能的代码,但我想问问你是否注意到任何重大的性能改进与安全的c#代码相比,使用它的真实世界的应用程序。真正不安全的代码性能
一个很好的例子是图像处理。通过使用指向字节的指针(这需要不安全的代码)来修改像素速度要快很多。
实施例:http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx
如此说来,对于大多数情况,差异不会像明显。因此,在使用不安全的代码之前,请对应用程序进行配置以查看性能瓶颈的位置,并测试不安全的代码是否是真正的解决方案,以使其更快。
安全图像处理也可以相当快。特别是如果您的算法可以写入以消除边界检查。我只使用不安全的代码将数据从位图复制到数组中并返回。如果你使用byte [],你甚至可以避免使用'Marshal'函数。 – CodesInChaos 2011-03-21 08:40:37
@ Botz3000:这是一个很好的链接(期待阅读网站的其余部分),但结论是不健全的。使用'GetPixel'和'SetPixel' _is_真的很慢,但使用'int []'或多或少像使用没有缺点的指针一样快。 – 2012-07-10 09:01:06
@CodeInChaos:我必须同意。我得出的结论是唯一受益的方面是复制位图数据。尽管如此,还没有尝试过使用'元帅'。 – 2012-07-10 09:02:28
正如其他帖子所述,您可以使用可以在非常专业的环境中使用不安全的代码,以获得显着的性能提升。其中一种情况是迭代数组值类型。使用不安全的指针运算比使用for循环/索引的通常模式快得多..
struct Foo
{
int a = 1;
int b = 2;
int c = 0;
}
Foo[] fooArray = new Foo[100000];
fixed (Foo* foo = fooArray) // foo now points to the first element in the array...
{
var remaining = fooArray.length;
while (remaining-- > 0)
{
foo->c = foo->a + foo->b;
foo++; // foo now points to the next element in the array...
}
}
这里的主要好处是,我们已经削减了数组索引完全检查..
虽然很高性能,这种代码很难处理,可能是相当危险的(不安全),并且破坏了一些基本的准则(可变结构)。但是,确实有一些场景中,这是合适的......
这种代码的另一个重大缺陷是C#程序员中很大一部分人不了解它或其含义。如果你在一个团队工作,采用KISS原则... – MattDavey 2011-03-21 09:12:02
你确定这个特定的例子更快吗? Sun的JVM使用指针算法使这种类型的代码(Java或Scala)几乎与C++一样快;我很惊讶C#实现不会这么做。 – 2011-03-21 16:16:45
这个特殊的例子,不,因为编译器可以确定** i **永远不会超出数组的边界,因此跳过数组边界检查。但原则依然存在。在我的具体情况下,我有一个使用数组实现的环形缓冲区,以及一个迭代它的独立Iterator对象。在这种情况下,编译器无法进行此优化.. – MattDavey 2011-03-21 16:58:52
一些性能测量
的性能优势并不像你想象的那么大。
我做了一些正常的托管数组访问与C#中的不安全指针的性能测量。从Visual Studio 2010,.NET 4之外运行构建
结果,使用 任何CPU |发布基于以下PC规格:基于x64的PC,1个四核处理器。 Intel64家族6型号23步进10 GenuineIntel〜2833Mhz。
Linear array access 00:00:07.1053664 for Normal 00:00:07.1197401 for Unsafe *(p + i) Linear array access - with pointer increment 00:00:07.1174493 for Normal 00:00:10.0015947 for Unsafe (*p++) Random array access 00:00:42.5559436 for Normal 00:00:40.5632554 for Unsafe Random array access using Parallel.For(), with 4 processors 00:00:10.6896303 for Normal 00:00:10.1858376 for Unsafe
注意,不安全*(p++)
成语居然跑慢。我猜想这打破了一个编译器优化,它结合了循环变量和安全版本中的(编译器生成的)指针访问。
源代码可在github。
嗯,我建议阅读这个博客员额:MSDN blogs: Array Bounds Check Elimination in the CLR
这澄清越界检查如何在C#中进行。而且,Thomas Bratts测试对我来说似乎没用(看代码),因为JIT无论如何都会在他的“保存”循环中删除绑定检查。
你可以在这里总结这篇文章。如果链接变黑,你的回答不会很有帮助。 – ChrisF 2012-09-30 20:32:58
您已经错过了测试的要点 - 它们不会显示边界检查与不安全的效果。他们要证明边界检查经常被优化,而且在这些情况下不安全的代价可能是不值得的。 – 2013-03-25 15:57:48
我对视频操作代码使用不安全的代码。 在这样的代码中,您希望它在没有对值进行内部检查的情况下尽可能快地运行。没有不安全的属性,我可能无法跟上30fps或60 fps的视频流。 (取决于使用的相机)。
但是由于速度它被代码图形的人广泛使用。
P/Invoke与'unsafe'不太一样......我不确定推理如下...另外:你是否测量了一下,看看你是否在做一些有用的事情? – 2011-03-21 07:21:02
既不安全也不安全的应该是事实上更高性能的。总体性能取决于您在代码中实现的算法。 – zerkms 2011-03-21 07:22:11
我现在没有使用不安全的代码。我只是想了解是否值得将代码的关键部分更改为不安全的代码。 – Miguel 2011-03-21 07:23:49