【问题标题】:What is the fastest (possibly unsafe) way to read a byte[]?读取字节 [] 的最快(可能不安全)方法是什么?
【发布时间】:2011-03-04 15:12:32
【问题描述】:

我正在使用 C# 开发一个服务器项目,在收到 TCP 消息后,它被解析并存储在一个精确大小的 byte[] 中。 (不是固定长度的缓冲区,而是存储所有数据的绝对长度的 byte[]。)

现在为了阅读这个字节[],我将创建一些包装函数(也是为了兼容性),这些是我需要的所有函数的签名:

public byte ReadByte();
public sbyte ReadSByte();
public short ReadShort();
public ushort ReadUShort();
public int ReadInt();
public uint ReadUInt();
public float ReadFloat();
public double ReadDouble();
public string ReadChars(int length);
public string ReadString();

该字符串是一个以 \0 结尾的字符串,并且可能以 ASCII 或 UTF-8 编码,但我无法确定这一点,因为我不是在编写客户端。

数据存在于:

byte[] _data;
int _offset;

现在我可以手动编写所有这些函数,如下所示:

public byte ReadByte()
{
    return _data[_offset++];
}

public sbyte ReadSByte()
{
    byte r = _data[_offset++];
    if (r >= 128) return (sbyte)(r - 256);
    else return (sbyte)r;
}

public short ReadShort()
{
    byte b1 = _data[_offset++];
    byte b2 = _data[_offset++];
    if (b1 >= 128) return (short)(b1 * 256 + b2 - 65536);
    else return (short)(b1 * 256 + b2);
}

public short ReadUShort()
{
    byte b1 = _data[_offset++];
    return (short)(b1 * 256 + _data[_offset++]);
}

但我想知道是否有更快的方法,不排除使用不安全代码,因为这似乎花费了太多时间来进行简单处理。

【问题讨论】:

    标签: c# multithreading buffer


    【解决方案1】:

    查看 System 命名空间中的 BitConverter 类。它包含将部分 byte[]s 转换为其他原始类型的方法。我在类似的情况下使用过它,并且发现它非常快。

    至于从 byte[]s 解码字符串,请使用派生自 System.Text 命名空间中的 Encoding 类的类,特别是 GetString(byte[]) 方法(及其重载)。

    【讨论】:

    • 我知道 BitConverter 类,我会再试一次,但我认为上次尝试时出了点问题。
    • 如果您想发布另一个关于您使用 BitConverter 的问题的问题,请在此处发布该问题的链接,我会看看。
    • 我又发现了问题,如果byte[] _data = { 2, 1, 0, 9 };,那么BitConverter.ToInt32(_data, 0)的结果是:{9, 0, 1, 2} -> INT32
    • 对于 Encoding.(encoding type).GetString(),如何设置它以将其读取为 \0 终止的字符串?因为他们默认读取一个以长度为前缀的字符串。
    • 所以要改变它我只需要反转数据,但是读取字符串怎么样?
    【解决方案2】:

    一种方法是将数组的内容映射到结构(假设您的结构确实是静态的):

    http://geekswithblogs.net/taylorrich/archive/2006/08/21/88665.aspx

    using System;
    using System.Runtime.InteropServices;
    
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    struct Message
    {
        public int id;
        [MarshalAs (UnmanagedType.ByValTStr, SizeConst=50)] 
        public string text;
    }
    
    void OnPacket(byte[] packet)
    {
        GCHandle pinnedPacket = GCHandle.Alloc(packet, GCHandleType.Pinned);
        Message msg = (Message)Marshal.PtrToStructure(
            pinnedPacket.AddrOfPinnedObject(),
            typeof(Message));        
        pinnedPacket.Free();
    }
    

    【讨论】:

    • 一个有趣的方法 - 我想知道它是否更快。可能需要对这些进行基准测试...谢谢 =)
    • 这实际上不是我想要的,也不是静态的。
    【解决方案3】:

    您可以使用BinaryReader

    BinaryReader 是一个流装饰器,因此您必须将 byte[] 包装在 MemoryStream 中或将 Reader 直接附加到网络流。

    然后你就有了

    int ReadInt32()
    char[] ReadChars(int count)
    

    等等。


    编辑:显然你想要“更快的执行”。

    这意味着在通过(网络)I/O 接收到这些字节之后,您正在寻找对来自byte[] 的转换的优化。

    换句话说,您正在尝试优化只占用(估计)0.1% 时间的部分。完全是徒劳的。

    【讨论】:

    • 我知道,但这肯定不会更快,因为您需要将数据包装在内存流中,然后在二进制读取器中,二进制读取器在实际解析之前将其包装到内存流中.
    • @Aidia,您的问题不清楚您真正想要什么。在最后一句中,您谈到了工作量,这是另一个更快的问题。一个更理智的。我会编辑。
    猜你喜欢
    • 1970-01-01
    • 2016-02-14
    • 1970-01-01
    • 2021-12-08
    • 2011-08-11
    • 2011-10-26
    • 2013-05-12
    • 1970-01-01
    • 2021-09-14
    相关资源
    最近更新 更多