我可以将它与字节一起用于其他类型的值/对象吗?
can i use this same as with byte to other types values / objects?
因为我的目标是超越 List<T>
我正在测试数组,发现很少有起点可以进行测试
在尝试从屏幕上捕获位图之前,我已经对此进行了测试,
并且测试证明使用是足够的。
我的问题是什么数据类型可以使用这个 Copy() 代码除了 byte[]
假设我想要一个数据存储单元来利用非托管/不安全
public unsafe struct NusT
{
public unsafe int vi;
public unsafe bool vb;
}
而不是填充列表
我按如下方式初始化结构:1)
NusT n;
n.vi= 90;
n.vb=true
我在测试以下内容后测试了这个:2)
NusT n = new NusT(){vi=90, vb=true};
此测试是在测试之后:3)
NusT n = new NusT("90", true);
我认为最后两个结果相同但第一个非常快,因为我没有创建对象所以
NusT n-> instructions- 1
n.vi=90 -> instructions- 1
n.vb=true -> instructions- 1
现在我尽量减少了我能做的,这从 class 开始:
比上面的 2 和 3 还要糟糕,因为它还使用属性
class bigAndSlow
{
public int a { get; private set;}
public bool b { get; private set;}
public string c { get; private set;}
public bigAndSlow(int .. ,boo .. , string.. )
{
initialise ...
}
}
所以现在当最终决定是
public unsafe struct NusT
{
public unsafe int vi;
public unsafe bool vb;
}
我如何实现这个超快的数据单元以在
上使用 Copy()
NusT[] NustyArr;
static unsafe void Copy(byte[] src, int srcIndex,
byte[] dst, int dstIndex, int count)
{
if (src == null || srcIndex < 0 ||
dst == null || dstIndex < 0 || count < 0)
{
throw new ArgumentException();
}
int srcLen = src.Length;
int dstLen = dst.Length;
if (srcLen - srcIndex < count ||
dstLen - dstIndex < count)
{
throw new ArgumentException();
}
// The following fixed statement pins the location of
// the src and dst objects in memory so that they will
// not be moved by garbage collection.
fixed (byte* pSrc = src, pDst = dst)
{
byte* ps = pSrc;
byte* pd = pDst;
// Loop over the count in blocks of 4 bytes, copying an
// integer (4 bytes) at a time:
for (int n = 0; n < count / 4; n++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
}
// Complete the copy by moving any bytes that weren't
// moved in blocks of 4:
for (int n = 0; n < count % 4; n++)
{
*pd = *ps;
pd++;
ps++;
}
}
}
static void Main(string[] args)
{
byte[] a = new byte[100];
byte[] b = new byte[100];
for (int i = 0; i < 100; ++i)
a[i] = (byte)i;
Copy(a, 0, b, 0, 100);
Console.WriteLine("The first 10 elements are:");
for (int i = 0; i < 10; ++i)
Console.Write(b[i] + " ");
Console.WriteLine("\n");
}
是的,您可以使用任何 blittable 类型来执行此操作。 blittable 类型是基本类型(整数和浮点类型,但不是 bool)、一维 blittable 类型数组和仅包含 blittable 类型字段的结构。
结构 NusT
不可 blittable,因为它包含 bool
字段。只需将其更改为 byte
,您将获得一个可复制的结构,您可以为其获取指针。
这是适用于任何类型的代码:
static unsafe void UnsafeCopy<T>(T[] src, int srcIndex, T[] dst, int dstIndex, int count) where T : struct
{
if (src == null || srcIndex < 0 || dst == null || dstIndex < 0 || count < 0 || srcIndex + count > src.Length || dstIndex + count > dst.Length)
{
throw new ArgumentException();
}
int elem_size = Marshal.SizeOf(typeof(T));
GCHandle gch1 = GCHandle.Alloc(src, GCHandleType.Pinned);
GCHandle gch2 = GCHandle.Alloc(dst, GCHandleType.Pinned);
byte* ps = (byte*)gch1.AddrOfPinnedObject().ToPointer() + srcIndex * elem_size;
byte* pd = (byte*)gch2.AddrOfPinnedObject().ToPointer() + dstIndex * elem_size;
int len = count * elem_size;
try
{
// Loop over the count in blocks of 4 bytes, copying an
// integer (4 bytes) at a time:
for (int n = 0; n < len / 4; n++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
}
// Complete the copy by moving any bytes that weren't
// moved in blocks of 4:
for (int n = 0; n < len % 4; n++)
{
*pd = *ps;
pd++;
ps++;
}
}
finally
{
gch1.Free();
gch2.Free();
}
}
但我强烈建议您使用 Array.Copy
。已经是最高效的数组复制方式了。请参阅下面复制 1M 元素数组的基准:
byte[] Array.Copy: 57,491 us
byte[] FastCopy: 138,198 us
byte[] JustCopy: 792,399 us
byte[] UnsafeCopy: 138,575 us
byte[] MemCpy: 57,667 us
NusT[] Array.Copy: 1,197 ms
NusT[] JustCopy: 1,843 ms
NusT[] UnsafeCopy: 1,550 ms
NusT[] MemCpy: 1,208 ms
FastCopy
是你的复制函数,UnsafeCopy
是我的模板函数,JustCopy
是一个简单的实现for (int i = 0; i < src.Length; i++) dst[i] = src[i];
。 MemCpy
是 msvcrt memcpy
函数的 PInvoke 调用。
结论是:在 C# 中使用指针来提高性能是一种不好的做法。 JIT 不会优化不安全的代码。最好的解决方案是将性能关键代码移动到本机 DLL。
因为我的目标是超越 List<T>
我正在测试数组,发现很少有起点可以进行测试
在尝试从屏幕上捕获位图之前,我已经对此进行了测试,
并且测试证明使用是足够的。
我的问题是什么数据类型可以使用这个 Copy() 代码除了 byte[]
假设我想要一个数据存储单元来利用非托管/不安全
public unsafe struct NusT
{
public unsafe int vi;
public unsafe bool vb;
}
而不是填充列表
我按如下方式初始化结构:1)
NusT n;
n.vi= 90;
n.vb=true
我在测试以下内容后测试了这个:2)
NusT n = new NusT(){vi=90, vb=true};
此测试是在测试之后:3)
NusT n = new NusT("90", true);
我认为最后两个结果相同但第一个非常快,因为我没有创建对象所以
NusT n-> instructions- 1
n.vi=90 -> instructions- 1
n.vb=true -> instructions- 1
现在我尽量减少了我能做的,这从 class 开始: 比上面的 2 和 3 还要糟糕,因为它还使用属性
class bigAndSlow
{
public int a { get; private set;}
public bool b { get; private set;}
public string c { get; private set;}
public bigAndSlow(int .. ,boo .. , string.. )
{
initialise ...
}
}
所以现在当最终决定是
public unsafe struct NusT
{
public unsafe int vi;
public unsafe bool vb;
}
我如何实现这个超快的数据单元以在
上使用 Copy()NusT[] NustyArr;
static unsafe void Copy(byte[] src, int srcIndex,
byte[] dst, int dstIndex, int count)
{
if (src == null || srcIndex < 0 ||
dst == null || dstIndex < 0 || count < 0)
{
throw new ArgumentException();
}
int srcLen = src.Length;
int dstLen = dst.Length;
if (srcLen - srcIndex < count ||
dstLen - dstIndex < count)
{
throw new ArgumentException();
}
// The following fixed statement pins the location of
// the src and dst objects in memory so that they will
// not be moved by garbage collection.
fixed (byte* pSrc = src, pDst = dst)
{
byte* ps = pSrc;
byte* pd = pDst;
// Loop over the count in blocks of 4 bytes, copying an
// integer (4 bytes) at a time:
for (int n = 0; n < count / 4; n++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
}
// Complete the copy by moving any bytes that weren't
// moved in blocks of 4:
for (int n = 0; n < count % 4; n++)
{
*pd = *ps;
pd++;
ps++;
}
}
}
static void Main(string[] args)
{
byte[] a = new byte[100];
byte[] b = new byte[100];
for (int i = 0; i < 100; ++i)
a[i] = (byte)i;
Copy(a, 0, b, 0, 100);
Console.WriteLine("The first 10 elements are:");
for (int i = 0; i < 10; ++i)
Console.Write(b[i] + " ");
Console.WriteLine("\n");
}
是的,您可以使用任何 blittable 类型来执行此操作。 blittable 类型是基本类型(整数和浮点类型,但不是 bool)、一维 blittable 类型数组和仅包含 blittable 类型字段的结构。
结构 NusT
不可 blittable,因为它包含 bool
字段。只需将其更改为 byte
,您将获得一个可复制的结构,您可以为其获取指针。
这是适用于任何类型的代码:
static unsafe void UnsafeCopy<T>(T[] src, int srcIndex, T[] dst, int dstIndex, int count) where T : struct
{
if (src == null || srcIndex < 0 || dst == null || dstIndex < 0 || count < 0 || srcIndex + count > src.Length || dstIndex + count > dst.Length)
{
throw new ArgumentException();
}
int elem_size = Marshal.SizeOf(typeof(T));
GCHandle gch1 = GCHandle.Alloc(src, GCHandleType.Pinned);
GCHandle gch2 = GCHandle.Alloc(dst, GCHandleType.Pinned);
byte* ps = (byte*)gch1.AddrOfPinnedObject().ToPointer() + srcIndex * elem_size;
byte* pd = (byte*)gch2.AddrOfPinnedObject().ToPointer() + dstIndex * elem_size;
int len = count * elem_size;
try
{
// Loop over the count in blocks of 4 bytes, copying an
// integer (4 bytes) at a time:
for (int n = 0; n < len / 4; n++)
{
*((int*)pd) = *((int*)ps);
pd += 4;
ps += 4;
}
// Complete the copy by moving any bytes that weren't
// moved in blocks of 4:
for (int n = 0; n < len % 4; n++)
{
*pd = *ps;
pd++;
ps++;
}
}
finally
{
gch1.Free();
gch2.Free();
}
}
但我强烈建议您使用 Array.Copy
。已经是最高效的数组复制方式了。请参阅下面复制 1M 元素数组的基准:
byte[] Array.Copy: 57,491 us
byte[] FastCopy: 138,198 us
byte[] JustCopy: 792,399 us
byte[] UnsafeCopy: 138,575 us
byte[] MemCpy: 57,667 us
NusT[] Array.Copy: 1,197 ms
NusT[] JustCopy: 1,843 ms
NusT[] UnsafeCopy: 1,550 ms
NusT[] MemCpy: 1,208 ms
FastCopy
是你的复制函数,UnsafeCopy
是我的模板函数,JustCopy
是一个简单的实现for (int i = 0; i < src.Length; i++) dst[i] = src[i];
。 MemCpy
是 msvcrt memcpy
函数的 PInvoke 调用。
结论是:在 C# 中使用指针来提高性能是一种不好的做法。 JIT 不会优化不安全的代码。最好的解决方案是将性能关键代码移动到本机 DLL。