![](/img/trans.png)
[英]C# - Fastest way to convert an int and put it in a byte array with an offset
[英]Fastest way to convert int to 4 bytes in C#
在C#中將int轉換為4字節的最快方法是什么?
執行時間最快而不是開發時間。
我自己的解決方案是這個代碼:
byte[] bytes = new byte[4];
unchecked
{
bytes[0] = (byte)(data >> 24);
bytes[1] = (byte)(data >> 16);
bytes[2] = (byte)(data >> 8);
bytes[3] = (byte)(data);
}
現在我看到我的解決方案優於struct
和BitConverter
幾個滴答。
我認為不安全可能是最快的選擇,並接受這個作為答案,但我更喜歡使用托管選項。
在C#中將int轉換為4字節的最快方法是什么?
使用BitConverter ,它的GetBytes重載采用32位整數:
int i = 123;
byte[] buffer = BitConverter.GetBytes(i);
使用不安全代碼的字節*轉換是迄今為止最快的:
unsafe static void Main(string[] args) {
int i = 0x12345678;
byte* pi = (byte*)&i;
byte lsb = pi[0];
// etc..
}
這就是BitConverter所做的,這段代碼避免了創建數組的成本。
我已經研究了將基本類型序列化為字節數組所需的時間。 當你已經有一個數組和偏移量來放置你的數據時,我就這樣做了。 我猜這是一個非常重要的案例,與理論相比,得到一個4字節的數組,因為當你序列化某些東西時,它正是你所需要的。 我已經發現什么方法的答案更快取決於你想要序列化的類型。 我嘗試過幾種方法:
m_Bytes[offset] = (byte)(value >> 8)
m_Bytes[offset] = (byte)((i >> 8) & 0xFF)
我跑了所有的測試10毫升。 以下是以毫秒為單位的結果
Long Int Short Byte Float Double 1 29 32 31 30 29 34 2 209 233 220 212 208 228 3 63 24 13 8 24 44 4 72 29 14
正如您所看到的那樣,對於long和double,不安全的方式要快得多(無符號版本與其簽名版本大致相同,因此它們不在表中)。 對於short / int / float,最快的方法是使用shift進行2/4/4分配。 對於字節,最快的顯然是簡單的賦值。 所以關於原始問題 - 分配方式是最好的。 這是以最快的方式執行此類功能的示例:
public static void WriteInt(byte[] buffer, int offset, int value)
{
m_BytesInt[offset] = (byte)(value >> 24);
m_BytesInt[offset + 1] = (byte)(value >> 16);
m_BytesInt[offset + 2] = (byte)(value >> 8);
m_BytesInt[offset + 3] = (byte) value;
}
PS測試在x64環境下運行,代碼在發布模式下編譯為cpu any(運行時為x64)。
最快的方法是使用包含4個字節的結構。
明顯快於BitConverter。
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx
有必要的屬性。
[StructLayout(LayoutKind.Explicit)]
struct FooUnion
{
[FieldOffset(0)]
public byte byte0;
[FieldOffset(1)]
public byte byte1;
[FieldOffset(2)]
public byte byte2;
[FieldOffset(3)]
public byte byte3;
[FieldOffset(0)]
public int integer;
}
請注意,BitConverter可能不是最快的,如下面的測試所示。
使用BitConverter
類,特別是采用Int32
參數的GetBytes
方法:
var myInt = 123;
var bytes = BitConverter.GetBytes(myInt);
您可以使用BitConverter.IsLittlEndian
根據CPU架構確定字節順序。
編輯:由於編譯器優化,下面的測試不是決定性的。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
[StructLayout(LayoutKind.Explicit)]
struct FooUnion
{
[FieldOffset(0)]
public byte byte0;
[FieldOffset(1)]
public byte byte1;
[FieldOffset(2)]
public byte byte2;
[FieldOffset(3)]
public byte byte3;
[FieldOffset(0)]
public int integer;
}
class Program
{
static void Main(string[] args)
{
testUnion();
testBitConverter();
Stopwatch Timer = new Stopwatch();
Timer.Start();
testUnion();
Timer.Stop();
Console.WriteLine(Timer.ElapsedTicks);
Timer = new Stopwatch();
Timer.Start();
testBitConverter();
Timer.Stop();
Console.WriteLine(Timer.ElapsedTicks);
Console.ReadKey();
}
static void testBitConverter()
{
byte[] UnionBytes;
for (int i = 0; i < 10000; i++)
{
UnionBytes = BitConverter.GetBytes(i);
}
}
static void testUnion()
{
byte[] UnionBytes;
for (int i = 0; i < 10000; i++)
{
FooUnion union = new FooUnion() { integer = i };
UnionBytes = new byte[] { union.byte0, union.byte1, union.byte2, union.byte3 };
}
}
}
}
這里的許多人似乎都在爭論BitConverter
是否比專用struct
更好。 基於BCL源代碼, BitConverter.GetBytes()
看起來像這樣:
public static unsafe byte[] GetBytes(int value)
{
byte[] buffer = new byte[4];
fixed (byte* bufferRef = buffer)
{
*((int*)bufferRef) = value;
}
return buffer;
}
從我的觀點來看,這比對這個顯式結構進行1個整數+ 4個字節賦值要快得多。
[StructLayout(LayoutKind.Explicit)]
struct IntByte
{
[FieldOffset(0)]
public int IntVal;
[FieldOffset(0)]
public byte Byte0;
[FieldOffset(1)]
public byte Byte1;
[FieldOffset(2)]
public byte Byte2;
[FieldOffset(3)]
public byte Byte3;
}
new IntByte { IntVal = 10 } -> Byte0, Byte1, Byte2, Byte3.
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
unsafe{
byte[] byteArray = new byte[4];
for(int i = 0; i != int.MaxValue; ++i)
{
fixed(byte* asByte = byteArray)
*((int*)asByte) = 43;
}
}
Console.WriteLine(sw.ElapsedMilliseconds);
Console.Read();
}
}
在我的機器上平均約2770毫秒
[StructLayout(LayoutKind.Explicit)]
struct Switcher
{
[FieldOffset(0)]
public int intVal;
[FieldOffset(0)]
public byte b0;
[FieldOffset(1)]
public byte b1;
[FieldOffset(2)]
public byte b2;
[FieldOffset(3)]
public byte b3;
}
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
byte[] byteArray = new byte[4];
Switcher swi = new Switcher();
for(int i = 0; i != int.MaxValue; ++i)
{
swi.intVal = 43;
byteArray[0] = swi.b0;
byteArray[1] = swi.b1;
byteArray[2] = swi.b2;
byteArray[3] = swi.b3;
}
Console.WriteLine(sw.ElapsedMilliseconds);
Console.Read();
}
}
平均值約為4510毫秒。
我認為這可能是C#中最快的方式..(字節數組初始化為int流w / int32的4倍
private MemoryStream Convert(int[] Num, byte[] Bytes)
{
Buffer.BlockCopy(Num, 0, Bytes, 0, Bytes.Length);
MemoryStream stream = new MemoryStream(Bytes);
return stream;
}
Union是將整數拆分為字節的最快方法。 下面是一個完整的程序,其中C#優化器無法優化字節拆分操作,因為每個字節相加並打印出總和。
我的筆記本電腦的時間為聯盟419毫秒, BitConverter為461毫秒 。 然而,速度增益要大得多。
此方法用於開源高性能算法HPCsharp庫,其中Union方法為Radix Sort提供了良好的性能提升。
Union更快,因為它不執行按位屏蔽而不執行位移,而只是從4字節整數中讀取正確的字節。
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace SplitIntIntoBytes
{
[StructLayout(LayoutKind.Explicit)]
struct FooUnion
{
[FieldOffset(0)]
public byte byte0;
[FieldOffset(1)]
public byte byte1;
[FieldOffset(2)]
public byte byte2;
[FieldOffset(3)]
public byte byte3;
[FieldOffset(0)]
public int integer;
}
class Program
{
static void Main(string[] args)
{
testUnion();
testBitConverter();
Stopwatch Timer = new Stopwatch();
Timer.Start();
int sumTestUnion = testUnion();
Timer.Stop();
Console.WriteLine("time of Union: " + Timer.ElapsedTicks + " milliseconds, sum: " + sumTestUnion);
Timer.Restart();
int sumBitConverter = testBitConverter();
Timer.Stop();
Console.WriteLine("time of BitConverter: " + Timer.ElapsedTicks + " milliseconds, sum: " + sumBitConverter);
Console.ReadKey();
}
static int testBitConverter()
{
byte[] UnionBytes = new byte[4];
byte[] SumOfBytes = new byte[4];
SumOfBytes[0] = SumOfBytes[1] = SumOfBytes[2] = SumOfBytes[3] = 0;
for (int i = 0; i < 10000; i++)
{
UnionBytes = BitConverter.GetBytes(i);
SumOfBytes[0] += UnionBytes[0];
SumOfBytes[1] += UnionBytes[1];
SumOfBytes[2] += UnionBytes[2];
SumOfBytes[3] += UnionBytes[3];
}
return SumOfBytes[0] + SumOfBytes[1] + SumOfBytes[2] + SumOfBytes[3];
}
static int testUnion()
{
byte[] UnionBytes;
byte[] SumOfBytes = new byte[4];
SumOfBytes[0] = SumOfBytes[1] = SumOfBytes[2] = SumOfBytes[3] = 0;
FooUnion union = new FooUnion();
for (int i = 0; i < 10000; i++)
{
union.integer = i;
UnionBytes = new byte[] { union.byte0, union.byte1, union.byte2, union.byte3 };
SumOfBytes[0] += UnionBytes[0];
SumOfBytes[1] += UnionBytes[1];
SumOfBytes[2] += UnionBytes[2];
SumOfBytes[3] += UnionBytes[3];
}
return SumOfBytes[0] + SumOfBytes[1] + SumOfBytes[2] + SumOfBytes[3];
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.