16

在我们的应用程序中,我们有一个非常大的字节数组,我们必须将这些字节转换为不同的类型。目前,我们BitConverter.ToXXXX()用于此目的。我们的重击手是,ToInt16ToUInt64

对于UInt64,我们的问题是数据流实际上有 6 个字节的数据来表示一个大整数。由于没有将 6 字节数据转换为 的本机函数UInt64,我们这样做:

UInt64 value = BitConverter.ToUInt64() & 0x0000ffffffffffff;

我们的使用ToInt16更简单,不用做任何位操作。

我们做了很多这两个操作,所以我想问 SO 社区是否有更快的方法来进行这些转换。目前,这两个函数消耗了我们整个 CPU 周期的大约 20%。

4

4 回答 4

8

你有没有想过直接使用内存指针。我不能保证它的性能,但它是 C++\C 中的一个常见技巧......

        byte[] arr = { 1, 2, 3, 4, 5, 6, 7, 8 ,9,10,11,12,13,14,15,16};

        fixed (byte* a2rr = &arr[0])
        {

            UInt64* uint64ptr = (UInt64*) a2rr;
            Console.WriteLine("The value is {0:X2}", (*uint64ptr & 0x0000FFFFFFFFFFFF));
            uint64ptr = (UInt64*) ((byte*) uint64ptr+6);
            Console.WriteLine("The value is {0:X2}", (*uint64ptr & 0x0000FFFFFFFFFFFF));
        }

您需要在构建设置中使您的程序集“不安全”,并标记您执行此操作的方法是不安全的。通过这种方法,您还与 little endian 相关联。

于 2011-02-07T19:15:59.773 回答
5

您可以使用System.Buffer该类将整个数组复制到另一个不同类型的数组,作为快速的“块复制”操作:

BlockCopy 方法使用内存中的偏移量访问 src 参数数组中的字节,而不是诸如索引或数组上下界之类的编程结构。

数组类型必须是“原始”类型,它们必须对齐,并且复制操作是字节序敏感的。在您使用 6 字节整数的情况下,它不能与 .NET 的任何“原始”类型对齐,除非您可以获得每六个填充两个字节的源数组,然后将对齐到Int64. 但是这种方法适用于 的数组Int16,这可能会加快您的某些操作。

于 2011-02-07T20:21:52.420 回答
2

为什么不:

UInt16 valLow = BitConverter.ToUInt16();
UInt64 valHigh = (UInt64)BitConverter.ToUInt32();
UInt64 Value = (valHigh << 16) | valLow;

尽管 JIT 编译器可能会自动为您执行此操作,但您可以只创建一条语句。

这将阻止您读取最终丢弃的额外两个字节。

如果这不会减少 CPU,那么您可能需要编写自己的转换器,直接从缓冲区读取字节。您可以使用数组索引,或者,如果您认为有必要,可以使用带有指针的不安全代码。

请注意,正如评论者指出的那样,如果您使用这些建议中的任何一个,那么您要么受限于特定的“字节序”,要么您必须编写代码来检测小/大字节序并做出相应的反应. 我上面展示的代码示例适用于小端(x86)。

于 2011-02-07T16:55:17.427 回答
1

在此处查看我对类似问题的回答。这与吉米的回答中的不安全内存操作相同,但对消费者来说更“友好”。它允许您将byte数组视为UInt64数组。

于 2012-05-10T03:59:26.270 回答