gpt4 book ai didi

C# - MemoryMarshal.Cast() 能否在 Linux 和 Windows 上转换任何具有兼容字节序的结构或原语

转载 作者:行者123 更新时间:2023-12-02 18:03:49 43 4
gpt4 key购买 nike

我正在寻找处理 PointF 类型数组的快速方法。用下面的代码转换它们给出了一个跨度,所以我可以使用 fma、avx 和 sse 内在函数来加速代码。此功能在我的机器上正常工作。问题在于安全。在不同平台上执行此类转换是否安全? Microsoft 文档说,大端架构可以在拆分或合并值时反转值:

https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.memorymarshal.cast?view=net-6.0#system-runtime-interopservices-memorymarshal-cast-2(system-span((-0)))

using System;
using System.Drawing;
using System.Runtime.InteropServices;

public static class PontFExtension
{
public static Span<float> AsSingleSpan(this PointF[] points)
{
var span = new Span<PointF>(points);

return MemoryMarshal.Cast<PointF, float>(span);
}
}

最佳答案

简短的回答是否定的,因为 PointFFloat是具有不同字段和布局的两个不同结构(即 PointF.X 和 PointF.Y 是 PointF 结构上的字段)。它可能适用于一种操作系统和 .Net 版本,但可能无法适用于其他版本。

我提供了三种跨操作系统和 .Net 版本安全实现目标的方法,确保您在 Span<float[]> 中获得 X 和 Y。 (参见实现多维)或在 Span<float> 中交替(请参阅实现单一维度)。

字节顺序

我提供的实现不会导致操作系统之间的字节顺序问题 - 即使类型被序列化并以一种格式(例如 Big)写入网络流并由 .Net 在另一种格式(例如 Little)中读取另一边 - 因为 .Net BCL 检查并相应地旋转位。

我不能对你使用 Marshal.Cast 的实现说同样的话因为 (i) 它是一种可能会根据 OS/.Net 版本产生不可预测结果的解决方案,并且 (ii) 我对内在函数的了解还不够多,无法发表意见 Marshal.Cast .如果我是你,我会保持简单并使用我建议的方法之一。

基准

Linq 是预期中最慢的。 AsSpanPtr 实现的“Ref”(迭代器引用)实现速度提高了 4 倍。以下 BenchmarkDotNet 结果是使用相同的集合进行 10M 次迭代。

| Method |      Mean |     Error |    StdDev | Ratio | RatioSD |
|------- |----------:|----------:|----------:|------:|--------:|
| Ptr | 6.762 ms | 0.0731 ms | 0.0648 ms | 1.00 | 0.00 |
| Ref | 27.169 ms | 0.4086 ms | 0.3822 ms | 4.02 | 0.06 |
| Linq | 31.896 ms | 0.4622 ms | 0.4098 ms | 4.72 | 0.08 |

实现多维

public static class PontFExtension
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<float[]> AsSpanLinq(this PointF[] points)
=> points.Select(x => new float[] { x.X, x.Y }).ToArray().AsSpan();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<float[]> AsSpanRef(this PointF[] points)
{
Span<float[]> floats = new float[points.Length][];
for (int i = 0; i < points.Length; i++)
{
PointF point = points[i];
floats[i] = new[] { point.X, point.Y };
}
return floats;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static Span<float[]> AsSpanPtr(this PointF[] points)
{
Span<float[]> floats = new float[points.Length][];
fixed (PointF* pinned = points)
{
for (int i = 0; i < points.Length; i++)
{
PointF* pnt = &pinned[i];
floats[i] = new[] { (*pnt).X, (*pnt).Y };
}
}
return floats;
}
}

实现 - 单一维度(每行 X 和 Y 交替)

public static unsafe class PontFExtensionSingleDimension
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<float> AsSpanLinq(this PointF[] points)
=> points.SelectMany(x => new[] { x.X, x.Y}).ToArray();

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span<float> AsSpanRef(this PointF[] points)
{
var len = points.Length;
Span<float> floats = new float[len * 2];
for (int i = 0; i < len; i++)
{
var pnt = points[i];
floats[i*2] = pnt.X; floats[i*2+1] = pnt.Y;
}
return floats;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe static Span<float> AsSpanPtr(this PointF[] points)
{
var len = points.Length;
Span<float> floats = new float[len * 2];
fixed (PointF* pinned = points)
{
for (int i = 0; i < len; i++)
{
PointF* pnt = &pinned[i];
floats[i*2] = (*pnt).X; floats[i*2+1] = (*pnt).Y ;
}
}
return floats;
}

}

关于C# - MemoryMarshal.Cast() 能否在 Linux 和 Windows 上转换任何具有兼容字节序的结构或原语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73748519/

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