繁体   English   中英

在C#中将int转换为4字节的最快方法

[英]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);
}

现在我看到我的解决方案优于structBitConverter几个滴答。

我认为不安全可能是最快的选择,并接受这个作为答案,但我更喜欢使用托管选项。

在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字节的数组,因为当你序列化某些东西时,它正是你所需要的。 我已经发现什么方法的答案更快取决于你想要序列化的类型。 我尝试过几种方法:

  1. 带有额外缓冲区溢出检查的不安全引用
  2. GetBytes +结果Buffer.BulkCopy(这与1加上开销基本相同)
  3. 使用shift进行直接赋值( m_Bytes[offset] = (byte)(value >> 8)
  4. 直接赋值为shift和bitwise& 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个字节的结构。

  • 在定义的布局中(在字节位置0,1,2,3
  • 以及从位置0开始的int32。
  • 输入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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM