c# – 最快的读写二进制方式

前端之家收集整理的这篇文章主要介绍了c# – 最快的读写二进制方式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在优化应用程序,经常做的操作之一是读写二进制.我需要2种功能
Set(byte[] target,int index,int value);

int Get(byte[] source,int index);

这些函数是签名和无符号的short,int和long在大而小的顺序排列中需要的.

以下是我做过的一些例子,但是我需要评估一下优点和缺点:

第一种方法是使用Marshal将值写入字节[]的内存中,第二种是使用纯指针来完成此操作,第三种方法使用BitConverter和BlockCopy来执行此操作

unsafe void Set(byte[] target,int value)
{
    fixed (byte* p = &target[0])
    {
        Marshal.WriteInt32(new IntPtr(p),index,value);
    }
}

unsafe void Set(byte[] target,int value)
{
    int* p = &value;
    for (int i = 0; i < 4; i++)
    {
        target[offset + i] = *((byte*)p + i);
    }
}

void Set(byte[] target,int value)
{
    byte[] data = BitConverter.GetBytes(value);
    Buffer.BlockCopy(data,target,data.Length);
}

这里是Read / Get方法

第一个是使用元帅从byte []读取值,第二个是使用plain指针,第三个是再次使用BitConverter:

unsafe int Get(byte[] source,int index)
{
    fixed (byte* p = &source[0])
    {
        return Marshal.ReadInt32(new IntPtr(p),index);
    }
}

unsafe int Get(byte[] source,int index)
{
    fixed (byte* p = &source[0])
    {
        return *(int*)(p + index);
    }
}

unsafe int Get(byte[] source,int index)
{
    return BitConverter.ToInt32(source,index);
}

边界检查需要做,但不是我的问题的一部分…

如果有人能够告诉我们,在这种情况下最好还是最快的方式是什么,或者给我一些其他的解决方案,我很高兴.一般的解决方案是最好的

我刚刚做了一些性能测试,这里有结果:

设置元组:45 ms,设置指针:48 ms,设置BitConverter:71 ms
获取元帅:45 ms,获取指针:26 ms,获取BitConverter:30 ms

似乎使用指针是快速的方式,但我认为Marshal和BitConverter做一些内部检查…有人可以验证吗?

解决方法

重要提示:如果只需要一个endian,请参考wj32 / dtb的指针魔术

就个人而言,我会直接写入一个Stream(可能有一些缓冲),并重新使用一般共享的缓冲区,我通常认为是干净的.那么你可以做一些快捷方式,并假设索引为0/1/2/3.

当然不要使用BitConverter,因为它不能用于您需要的小/大端.我也会倾向于使用位移而不是不安全的等等.它是以最快的速度,基于以下(所以我很高兴这是我已经做了我的代码here,寻找EncodeInt32Fixed):

Set1: 371ms
Set2: 171ms
Set3: 993ms
Set4: 91ms <==== bit-shifting ;-p

码:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
static class Program
{
    static void Main()
    {
        const int LOOP = 10000000,INDEX = 100,VALUE = 512;
        byte[] buffer = new byte[1024];
        Stopwatch watch;

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set1(buffer,INDEX,VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set1: " + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set2(buffer,VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set2: " + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set3(buffer,VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set3: " + watch.ElapsedMilliseconds + "ms");

        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            Set4(buffer,VALUE);
        }
        watch.Stop();
        Console.WriteLine("Set4: " + watch.ElapsedMilliseconds + "ms");

        Console.WriteLine("done");
        Console.ReadLine();
    }
    unsafe static void Set1(byte[] target,int value)
    {
        fixed (byte* p = &target[0])
        {
            Marshal.WriteInt32(new IntPtr(p),value);
        }
    }

    unsafe static void Set2(byte[] target,int value)
    {
        int* p = &value;
        for (int i = 0; i < 4; i++)
        {
            target[index + i] = *((byte*)p + i);
        }
    }

    static void Set3(byte[] target,int value)
    {
        byte[] data = BitConverter.GetBytes(value);
        Buffer.BlockCopy(data,data.Length);
    }
    static void Set4(byte[] target,int value)
    {
        target[index++] = (byte)value;
        target[index++] = (byte)(value >> 8);
        target[index++] = (byte)(value >> 16);
        target[index] = (byte)(value >> 24);
    }
}

猜你在找的C#相关文章