C# 是否可以创建性能类似System.Numerics.Vector4的自定义向量类型?

C# 是否可以创建性能类似System.Numerics.Vector4的自定义向量类型?,c#,.net,.net-core,C#,.net,.net Core,System.Numerics.Vector4类型有很好的性能,因为CLR可以优化它以使用矢量化的CPU指令。但是,我想创建自己的自定义4元素、单精度浮点向量类型,以便添加各种方便的方法和属性、属性、接口等。。。不幸的是,我自己的向量类型的性能不如System.Numerics.Vector4,即使它在内部使用System.Numerics.Vector4。有没有办法从自定义向量类型中获得类似System.Numerics.Vector4的性能 下面是一个程序,它试图(但大多失败)通过在自定义向

System.Numerics.Vector4
类型有很好的性能,因为CLR可以优化它以使用矢量化的CPU指令。但是,我想创建自己的自定义4元素、单精度浮点向量类型,以便添加各种方便的方法和属性、属性、接口等。。。不幸的是,我自己的向量类型的性能不如
System.Numerics.Vector4
,即使它在内部使用
System.Numerics.Vector4
。有没有办法从自定义向量类型中获得类似System.Numerics.Vector4的性能

下面是一个程序,它试图(但大多失败)通过在自定义向量类型中嵌套
System.Numerics.Vector4来提高性能:

using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;

class Program
{
    private const int ARR_LENGTH = 1000;
    private const int OUTER_LOOP = 1000000;

    static void Main(string[] args)
    {
        TestVector4();
        TestMyVector();
        TestMyVectorSimd();
    }

    static void TestVector4()
    {
        Vector4[] arr = new Vector4[ARR_LENGTH];
        for(int i = 0; i < arr.Length; i++)
            arr[i] = new Vector4(i, i, i, i);

        Stopwatch sw = Stopwatch.StartNew();
        Vector4 total = default;
        for(int i = 0; i < OUTER_LOOP; i++)
        {
            total = default;
            for(int j = 0; j < ARR_LENGTH; j++)
                total += arr[j];
        }
        sw.Stop();

        Console.WriteLine($"System.Numerics.Vector4: {total}  ({sw.Elapsed})");
    }

    static void TestMyVector()
    {
        MyVector[] arr = new MyVector[ARR_LENGTH];
        for(int i = 0; i < arr.Length; i++)
            arr[i] = new MyVector(i, i, i, i);

        Stopwatch sw = Stopwatch.StartNew();
        MyVector total = default;
        for(int i = 0; i < OUTER_LOOP; i++)
        {
            total = default;
            for(int j = 0; j < ARR_LENGTH; j++)
                total += arr[j];
        }
        sw.Stop();

        Console.WriteLine($"MyVector: {total}  ({sw.Elapsed})");
    }

    static void TestMyVectorSimd()
    {
        MyVectorSimd[] arr = new MyVectorSimd[ARR_LENGTH];
        for(int i = 0; i < arr.Length; i++)
            arr[i] = new MyVectorSimd(i, i, i, i);

        Stopwatch sw = Stopwatch.StartNew();
        MyVectorSimd total = default;
        for(int i = 0; i < OUTER_LOOP; i++)
        {
            total = default;
            for(int j = 0; j < ARR_LENGTH; j++)
                total += arr[j];
        }
        sw.Stop();

        Console.WriteLine($"MyVectorSimd: {total}  ({sw.Elapsed})");
    }
}

struct MyVector
{
    public float X, Y, Z, W;

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public MyVector(float x, float y, float z, float w)
    {
        X = x;
        Y = y;
        Z = z;
        W = w;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public override string ToString()
    {
        return $"<{X}, {Y}, {Z}, {W}>";
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public static MyVector operator +(MyVector left, MyVector right)
    {
        left.X += right.X;
        left.Y += right.Y;
        left.Z += right.Z;
        left.W += right.W;
        return left;
    }
}

struct MyVectorSimd
{
    public Vector4 V;

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public MyVectorSimd(float x, float y, float z, float w)
    {
        V = new Vector4(x, y, z, w);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public override string ToString()
    {
        return V.ToString();
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public static MyVectorSimd operator +(MyVectorSimd left, MyVectorSimd right)
    {
        left.V += right.V;
        return left;
    }
}
正如您所看到的,这两种自定义向量类型的性能都比
System.Numerics.Vector4
差得多,尽管内部使用
System.Numerics.Vector4
的类型仍然比不使用的类型好一点


所以重申一下我的问题,有没有办法让自定义向量类型与
System.Numerics.Vector4
一样执行?

多亏Christopher在对我的原始问题的评论中,我能够简单地将
in
关键字添加到
left
right
操作符参数中(重写它们以创建新的返回值,而不是修改
left
值)足以触发优化。此更新的代码为所有三个向量变量提供了基本相同的性能:

using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

class Program
{
    private const int ARR_LENGTH = 1000;
    private const int OUTER_LOOP = 1000000;

    static void Main(string[] args)
    {
        TestVector4();
        TestMyVector();
        TestMyVectorSimd();
    }

    static void TestVector4()
    {
        Vector4[] arr = new Vector4[ARR_LENGTH];
        for(int i = 0; i < arr.Length; i++)
            arr[i] = new Vector4(i, i, i, i);

        Stopwatch sw = Stopwatch.StartNew();
        Vector4 total = default;
        for(int i = 0; i < OUTER_LOOP; i++)
        {
            total = default;
            for(int j = 0; j < ARR_LENGTH; j++)
                total += arr[j];
        }
        sw.Stop();

        Console.WriteLine($"System.Numerics.Vector4: {total}  ({sw.Elapsed})");
    }

    static void TestMyVector()
    {
        MyVector[] arr = new MyVector[ARR_LENGTH];
        for(int i = 0; i < arr.Length; i++)
            arr[i] = new MyVector(i, i, i, i);

        Stopwatch sw = Stopwatch.StartNew();
        MyVector total = default;
        for(int i = 0; i < OUTER_LOOP; i++)
        {
            total = default;
            for(int j = 0; j < ARR_LENGTH; j++)
                total += arr[j];
        }
        sw.Stop();

        Console.WriteLine($"MyVector: {total}  ({sw.Elapsed})");
    }

    static void TestMyVectorSimd()
    {
        MyVectorSimd[] arr = new MyVectorSimd[ARR_LENGTH];
        for(int i = 0; i < arr.Length; i++)
            arr[i] = new MyVectorSimd(i, i, i, i);

        Stopwatch sw = Stopwatch.StartNew();
        MyVectorSimd total = default;
        for(int i = 0; i < OUTER_LOOP; i++)
        {
            total = default;
            for(int j = 0; j < ARR_LENGTH; j++)
                total += arr[j];
        }
        sw.Stop();

        Console.WriteLine($"MyVectorSimd: {total}  ({sw.Elapsed})");
    }
}

struct MyVector
{
    public float X, Y, Z, W;

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public MyVector(float x, float y, float z, float w)
    {
        X = x;
        Y = y;
        Z = z;
        W = w;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public override string ToString()
    {
        return $"<{X}, {Y}, {Z}, {W}>";
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public static MyVector operator +(in MyVector left, in MyVector right)
    {
        return new MyVector(left.X + right.X, left.Y + right.Y, left.Z + right.Z, left.W + right.W);
    }
}

struct MyVectorSimd
{
    public Vector4 V;

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public MyVectorSimd(float x, float y, float z, float w)
        : this()
    {
        V = new Vector4(x, y, z, w);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public MyVectorSimd(Vector4 v)
        : this()
    {
        V = v;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public override string ToString()
    {
        return V.ToString();
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
    public static MyVectorSimd operator +(in MyVectorSimd left, in MyVectorSimd right)
    {
        return new MyVectorSimd(left.V + right.V);
    }
}
使用系统;
使用系统诊断;
使用系统数字;
使用System.Runtime.CompilerServices;
使用System.Runtime.InteropServices;
班级计划
{
专用常量int ARR_LENGTH=1000;
外部循环的私有常量=1000000;
静态void Main(字符串[]参数)
{
TestVector4();
TestMyVector();
TestMyVectorSimd();
}
静态void TestVector4()
{
向量4[]arr=新向量4[arr_长度];
对于(int i=0;i
结果:

System.Numerics.Vector4: <499500, 499500, 499500, 499500>  (00:00:00.9987530)
MyVector: <499500, 499500, 499500, 499500>  (00:00:01.0064586)
MyVectorSimd: <499500, 499500, 499500, 499500>  (00:00:00.9739642)
System.Numerics.Vector4:(00:00:00.9987530)
MyVector:(00:00:01.0064586)
MyVectorSimd:(00:00:00.9739642)

编辑:这对Vector4有效,但无论出于何种原因,对Vector2或Vector3无效。仍在寻找如何创建与System.Numerics中的性能类似的自定义Vector2或Vector3的答案。

多亏Christopher在对我原始问题的评论中,我才能够找出simp将
in
关键字添加到
left
right
运算符参数中(并重写它们以创建新的返回值,而不是修改
l
System.Numerics.Vector4: <499500, 499500, 499500, 499500>  (00:00:00.9987530)
MyVector: <499500, 499500, 499500, 499500>  (00:00:01.0064586)
MyVectorSimd: <499500, 499500, 499500, 499500>  (00:00:00.9739642)