gpt4 book ai didi

c# - .NET 等同于 _byteswap_ulong/OSSwapInt32/或 bswap32

转载 作者:太空狗 更新时间:2023-10-30 00:15:05 25 4
gpt4 key购买 nike

有人知道是否有 .NET Framework 等效于交换 uint 中的字节顺序吗?

我正在尝试移植一些使用 MSFT 的自定义 C 哈希代码 _byteswap_ulong (相当于 *Nix 世界中的 Apples OSSwapInt32 或 Bswap32)到 c#。我可以手动编写此函数,但我怀疑它是否会利用任何编译器优化(例如,c/c++ 编译器提供了难以超越的内在函数,我希望运行时对内置功能执行相同的操作)。如果这很重要,我不关心保留字节顺序。

我已经尝试过基于通用的解决方案,但我不认为这是最优的。

BitConverter.ToUInt32(BitConverter.GetBytes(g).Reverse().ToArray<byte>(),0);

编辑:

所以我计算出这个特定函数在十分钟内平均被调用了多少次(对于我们的一个哈希消费者)。此函数被调用 10,000,000,000 次。因此,我设置了一些微观分析,以查看 C 代码与下面提供的解决方案(以及上面提出的解决方案)的性能。

C 代码运行那么多操作(使用内在函数)大约在在我可信赖的笔记本电脑上为 1500 毫秒。我在上面展示的 c# 代码运行时间将近 2,689,581 毫秒。一个巨大的差异。Matthew Watson 提供的 c# 代码运行时间接近 36000 毫秒。Caramiriel 提出的第一个解决方案运行了将近 115,014 毫秒,而提供的第二个解决方案运行了将近 36000 毫秒。

虽然这些解决方案都无法接近内部调用的速度,但它们比我原来的解决方案要好得多(对于这么多计算,从 44 分钟缩短到 36 秒)。这对我的应用程序来说是完全可以接受的。如果 .NET 编译器提供一些与 native 编译器相同的内在功能,那就太好了。

为了完整起见,这里是我的微基准测试 C 代码:

#include "stdafx.h"
#include "windows.h"

unsigned long Swap(unsigned int value)
{
return _byteswap_uint64(value);
}

int _tmain(int argc, _TCHAR* argv[])
{
unsigned int value = 0x01020304;
unsigned long NUMITER = 10000000000;
unsigned long a=0;
unsigned long z=0;
int throwAwayLoopCount = 5;

for (int k = 0; k < throwAwayLoopCount; ++k)
{
a = GetTickCount();
for (unsigned long i = 0; i < NUMITER; ++i)
{
value = Swap(value);
}
z = GetTickCount();
printf("Baseline, Cached: time is %4lld milliseconds: value%4lld\n", z-a,value);
}

printf("Baseline, Cached: time is %4lld milliseconds\n", z-a);

return 0;
}

这是用于对所提供的解决方案进行基准测试的 C# 代码:

namespace ByteSwapProfiler
{
using System.Runtime.InteropServices;
using System.Diagnostics;

[StructLayout(LayoutKind.Explicit)]
internal struct UInt32Union
{
[FieldOffset(0)]
public UInt32 Value;
[FieldOffset(0)]
public byte Byte1;
[FieldOffset(1)]
public byte Byte2;
[FieldOffset(2)]
public byte Byte3;
[FieldOffset(3)]
public byte Byte4;
}


class Program
{

static uint ByteSwapNaive(uint g)
{
return BitConverter.ToUInt32(BitConverter.GetBytes(g).Reverse().ToArray<byte>(), 0);
}

static uint ByteSwapCaramiriel1(uint value)
{
unchecked
{
return ((value & 0xff000000) >> 24) |
((value & 0x00ff0000) >> 8) |
((value & 0x0000ff00) << 8) |
((value & 0x000000ff) << 24);
}
}

static uint ByteSwapCaramiriel2(UInt32Union src)
{
UInt32Union dest = new UInt32Union
{
Byte1 = src.Byte4,
Byte2 = src.Byte3,
Byte3 = src.Byte2,
Byte4 = src.Byte1
};

return dest.Value;
}

static uint ByteSwapMatthewWatson(uint word)
{
return ((word >> 24) & 0x000000FF) | ((word >> 8) & 0x0000FF00) | ((word << 8) & 0x00FF0000) | ((word << 24) & 0xFF000000);
}

static void Main(string[] args)
{
uint value= 0x01020304;
UInt32Union src = new UInt32Union();
src.Value = value;

ulong NUMITER = 10000000000;
uint throwAwayLoopCount = 5;
var sw = new Stopwatch();
string name = "Naive";
//for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapNaive(value);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"),value);
}

Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));


name = "MatthewWatson";
for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapMatthewWatson(value);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"), value);
}
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));

name = "Caramiriel2";
for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapCaramiriel2(src);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"), value);
}

Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));

name = "Caramiriel1";
for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapCaramiriel1(value);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"), value);
}

Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));
}
}
}

最佳答案

从 .NET Core 2.1 开始,BinaryPrimitives.ReverseEndianness 为该功能提供了优化的软件实现。从 .NET Core 3.0 开始,它是通过 JIT 内在函数实现的,该内在函数被编译成使用 bswap 指令的非常高效的机器代码。

关于c# - .NET 等同于 _byteswap_ulong/OSSwapInt32/或 bswap32,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17251700/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com