将字节数组转换为 int 的更快方法
有没有比 < 更快的方法code>BitConverter.ToInt32 将字节数组转换为 int 值?
Is there a faster way than BitConverter.ToInt32
to convert a byte array to an int value?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我实际上尝试了几种不同的方法将四个字节转换为 int:
BitConverter.ToInt32(new byte[] { w, x, y, z }, 0);
BitConverter.ToUInt32(new byte[] { w, x, y, z }, 0);
b = new byte[] { w, x, y, z };
BitConverter.ToInt32(b, 0);
b = new byte[] { 1, 2, 3, 4, 5, 6, 7, w, x, y, z };
BitConverter.ToInt32(b, 7);
w | (x << 8) | (y << 16) | (y << 16) | (z << 24);
b[0] | (b[1] << 8) | (b[2] << 16) | (b[2] << 16) | (b[3] << 24);
我在发布 (x86) 版本中运行了 10^9 次迭代,而不是在 2.5 GHz Core i7 笔记本电脑。以下是我的结果(请注意,不使用 BitConverter 的方法要快得多):
您可以得出一些结论:
uint
代替int
可以节省少量时间。我不知道为什么,但我认为它小到足以成为实验误差。ToInt32
进行未对齐的数组访问会增加开销 (3ns)ToInt32
快几倍。最快的 test6 的运行时间仅为空循环(未显示)的两倍。换句话说,执行每次转换所需的时间不到 1ns。祝你好运,任何有用的计算都比这更快!
这是我的测试程序:
I actually tried several different ways to convert four bytes to an int:
BitConverter.ToInt32(new byte[] { w, x, y, z }, 0);
BitConverter.ToUInt32(new byte[] { w, x, y, z }, 0);
b = new byte[] { w, x, y, z };
BitConverter.ToInt32(b, 0);
b = new byte[] { 1, 2, 3, 4, 5, 6, 7, w, x, y, z };
BitConverter.ToInt32(b, 7);
w | (x << 8) | (y << 16) | (z << 24);
b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
I ran 10^9 iterations of each one in a Release (x86) build not on under a debugger on a 2.5 GHz Core i7 laptop. Here are my results (note that the methods that don't use
BitConverter
are substantially faster):Some conclusions you can draw:
uint
instead ofint
saves a small amount of time. I'm not sure why, but I think it's small enough to be experimental error.ToInt32
adds overhead (3ns)ToInt32
.The fastest, test6, took only twice as long to run as an empty loop (not shown). In other words, it took less than 1ns to perform each conversion. Good luck getting any useful calculation to go faster than that!
Here's my test program:
如果我没记错的话,该实现使用不安全的代码(将 byte* 视为 int*),因此很难击败,但另一种选择是移位。
然而,从该领域的大量工作来看,这不太可能成为真正的瓶颈,因此是无关紧要的。通常,I/O 是主要问题。
然而,由于数组/堆分配,GetBytes(int) 更昂贵(大量)。
If I remember correctly, that implementation uses unsafe code (treating a byte* as an int*), so it will be hard to beat, but the other alternative is shifting.
However, from lots of work in this area, this is so unlikely to be a genuine bottleneck as to be irrelevant. I/O is the main issue, typically.
GetBytes(int), however, is more expensive (in high volume) due to array / heap allocation.
Gabe 的性能测试的后续内容:
更改:
结果:
32 位选项:
<前><代码>测试3:00:00:06.9230577
测试5:00:00:03.8349386
测试6:00:00:03.8238272
测试7:00:00:07.3898489
测试8:00:00:04.6807391
64 位选项:
<前><代码>测试3:00:00:05.8794322
测试5:00:00:00.4384600
测试6:00:00:00.4069573
测试7:00:00:06.2279365
测试8:00:00:03.5472486
分析
守则
Followup to Gabe's performance tests:
Changes:
Results:
32-bit option:
64-bit option:
Analysis
BitConverter
overhead is the parameter checks it does?The Code
基于对
BitConverter.ToInt32 实施的快速回顾
在 .NET Reflector 中我会说“不”。它针对数组对齐并直接转换字节的情况进行优化,否则执行按位合并。
Based on a quick review of the implementation of
BitConverter.ToInt32
in .NET Reflector I would say "No".It optimises for the case where the array is aligned and directly casts the bytes, otherwise it performs a bitwise merge.
我总结了以上所有内容,添加了
Span
变体并使用了基准框架。I summarized all above, added a
Span
variant and used a benchmark framework.我也曾摆弄过类似的问题。
就我而言,当数据存储为双精度
byte[]
或仅在double
之间时,如何转换为单精度float
> 表示和byte[]
表示等。如果想要在大量数据上获得最佳性能,最好不要经过太多 API 层,并嵌入尽可能多的信息可以尽可能地融入到算法中,而不会使它变得太脆弱或难以理解。因此,为了进一步跟进 Richard 的 测试,我在下面添加了另一个测试 (
test9
),其中这是我在自己的工作中采用的方式,并在他的分析部分回答了他的第 4 点:使用不安全的内存指针访问来实现最高性能的结果。当然如果你使用c++,但不一定是c#。这类似于 BitConverter 在幕后所做的事情,但没有参数和安全检查(因为,当然,我们知道我们在做什么......;)
结果:
32 位选项:
<前><代码>测试3:00:00:06.2373138
测试5:00:00:03.1193338
测试6:00:00:03.1609287
测试7:00:00:07.7328020
测试8:00:00:06.4192130
测试9:00:00:03.9590307
64 位选项:
<预><代码>测试3:00:00:06.2209098
测试5:00:00:00.5563930
测试6:00:00:01.5486780
测试7:00:00:08.4858474
测试8:00:00:05.4991740
测试9:00:00:02.2928944
这里是相同的代码,包括新的
test9
:I have also fiddled with similar issues.
In my case it was how to convert to single precision
float
s when data is stored as double precisionbyte[]
s, or just between thedouble
representation and thebyte[]
representation etc. The best is not to go through too many API layers if one wants to achieve the best performance on large sets of data, and to embed as much info as you can into the algo as possible without making it too brittle or incomprehensible.So, to further follow up from Richard's tests, I add another test below (
test9
) which is the way I've gone in my own work and answers his point 4 in his Analysis section:Use unsafe memory pointer accessing to achieve the most performant result. Something that comes naturally if you use c++, but not necessarily c#. This is similar to what BitConverter is doing under the hood, but without the parameter and safety checks (as, of course, we know what we are doing... ;)
Results:
32-bit option:
64-bit option:
Here the same code, including the new
test9
: