主頁 > .NET開發 > .NET 向量型別的運算結果范例——用于學習Vector類所提供百多個向量方法

.NET 向量型別的運算結果范例——用于學習Vector類所提供百多個向量方法

2022-11-21 06:05:46 .NET開發

作者:

目錄
  • 一、背景
  • 二、撰寫Demo程式(VectorClassDemo)
    • 2.1 專案結構
    • 2.2 輸出環境資訊(OutputEnvironment)
    • 2.3 創建測驗資料(CreateVectorUseRotate)
    • 2.4 開始測驗(Run)
    • 2.5 測驗指定型別(RunType)
      • 2.5.1 非泛型的方法
      • 2.5.2 控制值的測驗
      • 2.5.3 out 引數
    • 2.6 格式化輸出(WriteLineFormat)
  • 三、運行結果
  • 參考文獻

目錄

    一、背景

    從.NET Core 1.0(或 .NET Framework 4.5、.NET Standard 1.0)開始,.NET中便可以使用具有SIMD硬體加速的向量型別了,
    其中大小與硬體相關的向量(Vectors with a hardware dependent size)作用最大,它由 只讀結構體(readonly struct) Vector<T>,及輔助的靜態類 Vector 所組成,
    只讀結構體 Vector<T> 主要是通過運算子提供了常規算術運算的能力,功能有限,而靜態類 Vector 為向量型別提供了大量的運算函式,能大大拓展了向量型別的使用領域,
    但是靜態類 Vector 提供了大量的方法,數量達到一百多個,且檔案說明很簡略,導致學習起來很困難,

    于是我撰寫了一個Demo程式,將靜態類 Vector所提供百多個向量方法,每一個均撰寫了測驗代碼,利用 測驗代碼、運行結果 與官方檔案進行對照,這樣便更容易弄懂了,

    二、撰寫Demo程式(VectorClassDemo)

    2.1 專案結構

    目前解決方案里有這3個專案:

    • VectorClassDemo:共享專案,里面是公用的測驗代碼,
    • VectorClassDemo20:.NET Core 2.0 控制臺專案,用于測驗低版本 .NET Core 2.0 時的運行情況,
    • VectorClassDemo50:Net 5.0 控制臺專案,用于測驗高版本 .NET 時的運行情況,例如可臨時將專案的目標框架修改為“.Net 7.0”,測驗 “.Net 7.0”下的表現,

    為了便于不同目標框架的測驗,于是將公用的測驗代碼放在共享專案里,這樣能便于代碼復用,使控制臺的代碼簡單,例如 VectorClassDemo50 中 Program.cs 代碼為:

    using System;
    using System.IO;
    using VectorClassDemo;
    
    namespace VectorClassDemo50 {
        class Program {
            static void Main(string[] args) {
                string indent = "";
                TextWriter tw = Console.Out;
                tw.WriteLine("VectorClassDemo50");
                tw.WriteLine();
                VectorDemo.OutputEnvironment(tw, indent);
                tw.WriteLine();
                VectorDemo.Run(tw, indent);
            }
        }
    }
    

    2.2 輸出環境資訊(OutputEnvironment)

    因為這次測驗了多個平臺,不同平臺的環境資訊資訊均不同,于是可以專門用一個函式來輸出環境資訊,原始碼如下,

    /// <summary>
    /// Is release make.
    /// </summary>
    public static readonly bool IsRelease =
    #if DEBUG
        false
    #else
        true
    #endif
    ;
    
    /// <summary>
    /// Output Environment.
    /// </summary>
    /// <param name="tw">Output <see cref="TextWriter"/>.</param>
    /// <param name="indent">The indent.</param>
    public static void OutputEnvironment(TextWriter tw, string indent) {
        if (null == tw) return;
        if (null == indent) indent = "";
        //string indentNext = indent + "\t";
        tw.WriteLine(indent + string.Format("IsRelease:\t{0}", IsRelease));
        tw.WriteLine(indent + string.Format("EnvironmentVariable(PROCESSOR_IDENTIFIER):\t{0}", Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER")));
        tw.WriteLine(indent + string.Format("Environment.ProcessorCount:\t{0}", Environment.ProcessorCount));
        tw.WriteLine(indent + string.Format("Environment.Is64BitOperatingSystem:\t{0}", Environment.Is64BitOperatingSystem));
        tw.WriteLine(indent + string.Format("Environment.Is64BitProcess:\t{0}", Environment.Is64BitProcess));
        tw.WriteLine(indent + string.Format("Environment.OSVersion:\t{0}", Environment.OSVersion));
        tw.WriteLine(indent + string.Format("Environment.Version:\t{0}", Environment.Version));
        //tw.WriteLine(indent + string.Format("RuntimeEnvironment.GetSystemVersion:\t{0}", System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion())); // Same Environment.Version
        tw.WriteLine(indent + string.Format("RuntimeEnvironment.GetRuntimeDirectory:\t{0}", System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()));
    #if (NET47 || NET462 || NET461 || NET46 || NET452 || NET451 || NET45 || NET40 || NET35 || NET20) || (NETSTANDARD1_0)
    #else
        tw.WriteLine(indent + string.Format("RuntimeInformation.FrameworkDescription:\t{0}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription));
    #endif
        tw.WriteLine(indent + string.Format("BitConverter.IsLittleEndian:\t{0}", BitConverter.IsLittleEndian));
        tw.WriteLine(indent + string.Format("IntPtr.Size:\t{0}", IntPtr.Size));
        tw.WriteLine(indent + string.Format("Vector.IsHardwareAccelerated:\t{0}", Vector.IsHardwareAccelerated));
        tw.WriteLine(indent + string.Format("Vector<byte>.Count:\t{0}\t# {1}bit", Vector<byte>.Count, Vector<byte>.Count * sizeof(byte) * 8));
        //tw.WriteLine(indent + string.Format("Vector<float>.Count:\t{0}\t# {1}bit", Vector<float>.Count, Vector<float>.Count * sizeof(float) * 8));
        //tw.WriteLine(indent + string.Format("Vector<double>.Count:\t{0}\t# {1}bit", Vector<double>.Count, Vector<double>.Count * sizeof(double) * 8));
        Assembly assembly;
        //assembly = typeof(Vector4).GetTypeInfo().Assembly;
        //tw.WriteLine(string.Format("Vector4.Assembly:\t{0}", assembly));
        //tw.WriteLine(string.Format("Vector4.Assembly.CodeBase:\t{0}", assembly.CodeBase));
        assembly = typeof(Vector<float>).GetTypeInfo().Assembly;
        tw.WriteLine(string.Format("Vector<T>.Assembly.CodeBase:\t{0}", assembly.CodeBase));
    
        OutputIntrinsics(tw, indent);
    }
    
    /// <summary>
    /// Output Intrinsics.
    /// </summary>
    /// <param name="tw">Output <see cref="TextWriter"/>.</param>
    /// <param name="indent">The indent.</param>
    public static void OutputIntrinsics(TextWriter tw, string indent) {
        if (null == tw) return;
        if (null == indent) indent = "";
    #if NETCOREAPP3_0_OR_GREATER
        tw.WriteLine();
        tw.WriteLine(indent + "[Intrinsics.X86]");
        WriteLineFormat(tw, indent, "Aes.IsSupported:\t{0}", System.Runtime.Intrinsics.X86.Aes.IsSupported);
        WriteLineFormat(tw, indent, "Aes.X64.IsSupported:\t{0}", System.Runtime.Intrinsics.X86.Aes.X64.IsSupported);
        WriteLineFormat(tw, indent, "Avx.IsSupported:\t{0}", Avx.IsSupported);
        WriteLineFormat(tw, indent, "Avx.X64.IsSupported:\t{0}", Avx.X64.IsSupported);
        WriteLineFormat(tw, indent, "Avx2.IsSupported:\t{0}", Avx2.IsSupported);
        WriteLineFormat(tw, indent, "Avx2.X64.IsSupported:\t{0}", Avx2.X64.IsSupported);
    #if NET6_0_OR_GREATER
        WriteLineFormat(tw, indent, "AvxVnni.IsSupported:\t{0}", AvxVnni.IsSupported);
        WriteLineFormat(tw, indent, "AvxVnni.X64.IsSupported:\t{0}", AvxVnni.X64.IsSupported);
    #endif
        WriteLineFormat(tw, indent, "Bmi1.IsSupported:\t{0}", Bmi1.IsSupported);
        WriteLineFormat(tw, indent, "Bmi1.X64.IsSupported:\t{0}", Bmi1.X64.IsSupported);
        WriteLineFormat(tw, indent, "Bmi2.IsSupported:\t{0}", Bmi2.IsSupported);
        WriteLineFormat(tw, indent, "Bmi2.X64.IsSupported:\t{0}", Bmi2.X64.IsSupported);
        WriteLineFormat(tw, indent, "Fma.IsSupported:\t{0}", Fma.IsSupported);
        WriteLineFormat(tw, indent, "Fma.X64.IsSupported:\t{0}", Fma.X64.IsSupported);
        WriteLineFormat(tw, indent, "Lzcnt.IsSupported:\t{0}", Lzcnt.IsSupported);
        WriteLineFormat(tw, indent, "Lzcnt.X64.IsSupported:\t{0}", Lzcnt.X64.IsSupported);
        WriteLineFormat(tw, indent, "Pclmulqdq.IsSupported:\t{0}", Pclmulqdq.IsSupported);
        WriteLineFormat(tw, indent, "Pclmulqdq.X64.IsSupported:\t{0}", Pclmulqdq.X64.IsSupported);
        WriteLineFormat(tw, indent, "Popcnt.IsSupported:\t{0}", Popcnt.IsSupported);
        WriteLineFormat(tw, indent, "Popcnt.X64.IsSupported:\t{0}", Popcnt.X64.IsSupported);
        WriteLineFormat(tw, indent, "Sse.IsSupported:\t{0}", Sse.IsSupported);
        WriteLineFormat(tw, indent, "Sse.X64.IsSupported:\t{0}", Sse.X64.IsSupported);
        WriteLineFormat(tw, indent, "Sse2.IsSupported:\t{0}", Sse2.IsSupported);
        WriteLineFormat(tw, indent, "Sse2.X64.IsSupported:\t{0}", Sse2.X64.IsSupported);
        WriteLineFormat(tw, indent, "Sse3.IsSupported:\t{0}", Sse3.IsSupported);
        WriteLineFormat(tw, indent, "Sse3.X64.IsSupported:\t{0}", Sse3.X64.IsSupported);
        WriteLineFormat(tw, indent, "Sse41.IsSupported:\t{0}", Sse41.IsSupported);
        WriteLineFormat(tw, indent, "Sse41.X64.IsSupported:\t{0}", Sse41.X64.IsSupported);
        WriteLineFormat(tw, indent, "Sse42.IsSupported:\t{0}", Sse42.IsSupported);
        WriteLineFormat(tw, indent, "Sse42.X64.IsSupported:\t{0}", Sse42.X64.IsSupported);
        WriteLineFormat(tw, indent, "Ssse3.IsSupported:\t{0}", Ssse3.IsSupported);
        WriteLineFormat(tw, indent, "Ssse3.X64.IsSupported:\t{0}", Ssse3.X64.IsSupported);
    #if NET5_0_OR_GREATER
        WriteLineFormat(tw, indent, "X86Base.IsSupported:\t{0}", X86Base.IsSupported);
        WriteLineFormat(tw, indent, "X86Base.X64.IsSupported:\t{0}", X86Base.X64.IsSupported);
    #endif // NET5_0_OR_GREATER
    #if NET7_0_OR_GREATER
        WriteLineFormat(tw, indent, "X86Serialize.IsSupported:\t{0}", X86Serialize.IsSupported);
        WriteLineFormat(tw, indent, "X86Serialize.X64.IsSupported:\t{0}", X86Serialize.X64.IsSupported);
    #endif // NET7_0_OR_GREATER
    #endif // NETCOREAPP3_0_OR_GREATER
    
    #if NET5_0_OR_GREATER
        tw.WriteLine();
        tw.WriteLine(indent + "[Intrinsics.Arm]");
        WriteLineFormat(tw, indent, "AdvSimd.IsSupported:\t{0}", AdvSimd.IsSupported);
        WriteLineFormat(tw, indent, "AdvSimd.Arm64.IsSupported:\t{0}", AdvSimd.Arm64.IsSupported);
        WriteLineFormat(tw, indent, "Aes.IsSupported:\t{0}", System.Runtime.Intrinsics.Arm.Aes.IsSupported);
        WriteLineFormat(tw, indent, "Aes.Arm64.IsSupported:\t{0}", System.Runtime.Intrinsics.Arm.Aes.Arm64.IsSupported);
        WriteLineFormat(tw, indent, "ArmBase.IsSupported:\t{0}", ArmBase.IsSupported);
        WriteLineFormat(tw, indent, "ArmBase.Arm64.IsSupported:\t{0}", ArmBase.Arm64.IsSupported);
        WriteLineFormat(tw, indent, "Crc32.IsSupported:\t{0}", Crc32.IsSupported);
        WriteLineFormat(tw, indent, "Crc32.Arm64.IsSupported:\t{0}", Crc32.Arm64.IsSupported);
        WriteLineFormat(tw, indent, "Dp.IsSupported:\t{0}", Dp.IsSupported);
        WriteLineFormat(tw, indent, "Dp.Arm64.IsSupported:\t{0}", Dp.Arm64.IsSupported);
        WriteLineFormat(tw, indent, "Rdm.IsSupported:\t{0}", Rdm.IsSupported);
        WriteLineFormat(tw, indent, "Rdm.Arm64.IsSupported:\t{0}", Rdm.Arm64.IsSupported);
        WriteLineFormat(tw, indent, "Sha1.IsSupported:\t{0}", Sha1.IsSupported);
        WriteLineFormat(tw, indent, "Sha1.Arm64.IsSupported:\t{0}", Sha1.Arm64.IsSupported);
        WriteLineFormat(tw, indent, "Sha256.IsSupported:\t{0}", Sha256.IsSupported);
        WriteLineFormat(tw, indent, "Sha256.Arm64.IsSupported:\t{0}", Sha256.Arm64.IsSupported);
    #endif // NET5_0_OR_GREATER
    }
    

    因向量型別與內在函式(Intrinsics Functions)緊密相關,于是該函式還輸出了各類內在函式的支持資訊,
    在開發程序中,發現 .NET 版本升級時也在增加更多的 內在函式(Intrinsics Functions),例如 Net 5.0 時增加了大量 Arm架構的內在函式,且增加了 X86Base,
    可以利用條件編譯,安全使用當前.NET 版本所允許使用的類,

    2.3 創建測驗資料(CreateVectorUseRotate)

    使用 Vector<T> 的建構式,只能創建單個數字重復的值,或是通過資料(或Span)逐一指定數字,前者太死板,后者又太繁瑣,因為在不同的處理器上,Vector<T>的長度是不同的,
    目前在支持 Avx2指令集的機器上,Vector<T>是256位的;而其他情況是 128位的,例如 128位的Vector<T>含有4個Single,而256位的Vector<T>含有8個Single,未來Vector<T>很可能會有512位或更高,
    對于測驗來說,很多時候我們用一批回圈數字就行,例如 128位時用 “a,b,c,d”,而256位時用“a,b,c,d,a,b,c,d”就好,
    于是我建立了一個根據有限資料來回圈鋪滿各個向量元素的函式,而且它是用 params 定義的可變引數,極大地方便了使用,代碼如下,

    /// <summary>
    /// Create Vector&lt;T&gt; use rotate.
    /// </summary>
    /// <typeparam name="T">Vector type.</typeparam>
    /// <param name="list">Source value list.</param>
    /// <returns>Returns Vector&lt;T&gt;.</returns>
    static Vector<T> CreateVectorUseRotate<T>(params T[] list) where T : struct {
        if (null == list || list.Length <= 0) return Vector<T>.Zero;
        T[] arr = new T[Vector<T>.Count];
        int idx = 0;
        for(int i=0; i< arr.Length; ++i) {
            arr[i] = list[idx];
            ++idx;
            if (idx >= list.Length) idx = 0;
        }
        Vector <T> rt = new Vector<T>(arr);
        return rt;
    }
    

    2.4 開始測驗(Run)

    有了CreateVectorUseRotate幫忙構造測驗資料后,我們可以很方便的建立測驗程式的骨架了,代碼如下:

    public static void Run(TextWriter tw, string indent) {
        RunType(tw, indent, CreateVectorUseRotate(float.MinValue, float.PositiveInfinity, float.NaN, -1.2f, 0f, 1f, 2f, 4f), new Vector<float>(2.0f));
        RunType(tw, indent, CreateVectorUseRotate(double.MinValue, double.PositiveInfinity, -1.2, 0), new Vector<double>(2.0));
        RunType(tw, indent, CreateVectorUseRotate<sbyte>(sbyte.MinValue, sbyte.MaxValue, -1, 0, 1, 2, 3, 4), new Vector<sbyte>(2));
        RunType(tw, indent, CreateVectorUseRotate<short>(short.MinValue, short.MaxValue, -1, 0, 1, 2, 3, 4, 127, 128), new Vector<short>(2));
        RunType(tw, indent, CreateVectorUseRotate<int>(int.MinValue, int.MaxValue, -1, 0, 1, 2, 3, 32768), new Vector<int>(2));
        RunType(tw, indent, CreateVectorUseRotate<long>(long.MinValue, long.MaxValue, -1, 0, 1, 2, 3), new Vector<long>(2));
        RunType(tw, indent, CreateVectorUseRotate<byte>(byte.MinValue, byte.MaxValue, 0, 1, 2, 3, 4), new Vector<byte>(2));
        RunType(tw, indent, CreateVectorUseRotate<ushort>(ushort.MinValue, ushort.MaxValue, 0, 1, 2, 3, 4, 255, 256), new Vector<ushort>(2));
        RunType(tw, indent, CreateVectorUseRotate<uint>(uint.MinValue, uint.MaxValue, 0, 1, 2, 3, 65536), new Vector<uint>(2));
        RunType(tw, indent, CreateVectorUseRotate<ulong>(ulong.MinValue, ulong.MaxValue, 0, 1, 2, 3), new Vector<ulong>(2));
    }
    

    2.5 測驗指定型別(RunType)

    RunType 是一個泛型函式,能夠分別測驗每一種數字型別,主要代碼如下,

    /// <summary>
    /// Run type demo.
    /// </summary>
    /// <typeparam name="T">Vector type.</typeparam>
    /// <param name="tw">Output <see cref="TextWriter"/>.</param>
    /// <param name="indent">The indent.</param>
    /// <param name="srcT">Source temp value.</param>
    /// <param name="src2">Source 2.</param>
    static void RunType<T>(TextWriter tw, string indent, Vector<T> srcT, Vector<T> src2) where T : struct {
        Vector<T> src0 = Vector<T>.Zero;
        Vector<T> src1 = Vector<T>.One;
        Vector<T> srcAllOnes = ~Vector<T>.Zero;
        int elementBitSize = (Vector<byte>.Count / Vector<T>.Count) * 8;
        tw.WriteLine(indent + string.Format("-- {0}, Vector<{0}>.Count={1} --", typeof(T).Name, Vector<T>.Count));
        WriteLineFormat(tw, indent, "srcT:\t{0}", srcT);
        //WriteLineFormat(tw, indent, "src2:\t{0}", src2);
        WriteLineFormat(tw, indent, "srcAllOnes:\t{0}", srcAllOnes);
    
        // -- Methods --
        #region Methods
        //Abs<T>(Vector<T>) Returns a new vector whose elements are the absolute values of the given vector's elements.
        WriteLineFormat(tw, indent, "Abs(srcT):\t{0}", Vector.Abs(srcT));
        WriteLineFormat(tw, indent, "Abs(srcAllOnes):\t{0}", Vector.Abs(srcAllOnes));
    
        //Add<T>(Vector<T>, Vector<T>) Returns a new vector whose values are the sum of each pair of elements from two given vectors.
        WriteLineFormat(tw, indent, "Add(srcT, src1):\t{0}", Vector.Add(srcT, src1));
        WriteLineFormat(tw, indent, "Add(srcT, src2):\t{0}", Vector.Add(srcT, src2));
    
        //AndNot<T>(Vector<T>, Vector<T>) Returns a new vector by performing a bitwise And Not operation on each pair of corresponding elements in two vectors.
        WriteLineFormat(tw, indent, "AndNot(srcT, src1):\t{0}", Vector.AndNot(srcT, src1));
        WriteLineFormat(tw, indent, "AndNot(srcT, src2):\t{0}", Vector.AndNot(srcT, src2));
    

    引數串列里有2個測驗用的向量值,分別是 srcT、src2,
    方法的頭部定義了一些常用的向量值,如:src0(0的值)、src1(1的值)、srcAllOnes(每個位全為1的值),隨后輸出 srcT、srcAllOnes 的值,便于口算資料,

    然后便是分別對 靜態類Vector 的各個方法進行測驗了,

    2.5.1 非泛型的方法

    靜態類Vector所提供的大部分方法是泛型方法,它們在RunType這樣的泛型方法內使用時是很方便的,
    但靜態類Vector的部分方法不是泛型方法,而是通過多載(overload)的方式提供各個型別的方法的,這時用起來麻煩一些,需要用 typeof 寫分支代碼,代碼如下,

    //ConvertToDouble(Vector<Int64>) Converts a Vector<Int64>to aVector<Double>.
    //ConvertToDouble(Vector<UInt64>) Converts a Vector<UInt64> to aVector<Double>.
    //ConvertToInt32(Vector<Single>) Converts a Vector<Single> to aVector<Int32>.
    //ConvertToInt64(Vector<Double>) Converts a Vector<Double> to aVector<Int64>.
    //ConvertToSingle(Vector<Int32>) Converts a Vector<Int32> to aVector<Single>.
    //ConvertToSingle(Vector<UInt32>) Converts a Vector<UInt32> to aVector<Single>.
    //ConvertToUInt32(Vector<Single>) Converts a Vector<Single> to aVector<UInt32>.
    //ConvertToUInt64(Vector<Double>) Converts a Vector<Double> to aVector<UInt64>.
    if (typeof(T) == typeof(Double)) {
        WriteLineFormat(tw, indent, "ConvertToInt64(srcT):\t{0}", Vector.ConvertToInt64(Vector.AsVectorDouble(srcT)));
        WriteLineFormat(tw, indent, "ConvertToUInt64(srcT):\t{0}", Vector.ConvertToUInt64(Vector.AsVectorDouble(srcT)));
    } else if (typeof(T) == typeof(Single)) {
        WriteLineFormat(tw, indent, "ConvertToInt32(srcT):\t{0}", Vector.ConvertToInt32(Vector.AsVectorSingle(srcT)));
        WriteLineFormat(tw, indent, "ConvertToUInt32(srcT):\t{0}", Vector.ConvertToUInt32(Vector.AsVectorSingle(srcT)));
    } else if (typeof(T) == typeof(Int32)) {
        WriteLineFormat(tw, indent, "ConvertToSingle(srcT):\t{0}", Vector.ConvertToSingle(Vector.AsVectorInt32(srcT)));
    } else if (typeof(T) == typeof(UInt32)) {
        WriteLineFormat(tw, indent, "ConvertToSingle(srcT):\t{0}", Vector.ConvertToSingle(Vector.AsVectorUInt32(srcT)));
    } else if (typeof(T) == typeof(Int64)) {
        WriteLineFormat(tw, indent, "ConvertToDouble(srcT):\t{0}", Vector.ConvertToDouble(Vector.AsVectorInt64(srcT)));
    } else if (typeof(T) == typeof(UInt64)) {
        WriteLineFormat(tw, indent, "ConvertToDouble(srcT):\t{0}", Vector.ConvertToDouble(Vector.AsVectorUInt64(srcT)));
    }
    

    2.5.2 控制值的測驗

    部分方法具有控制引數,如進行左移位的ShiftLeft,于是最好寫一個回圈,分別測驗不同的控制值,代碼如下,

    #if NET7_0_OR_GREATER
    //ShiftLeft(Vector<Byte>, Int32)  Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<Int16>, Int32) Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<Int32>, Int32) Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<Int64>, Int32) Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<IntPtr>, Int32)    Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<SByte>, Int32) Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<UInt16>, Int32)    Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<UInt32>, Int32) Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<UInt64>, Int32)    Shifts each element of a vector left by the specified amount.
    //ShiftLeft(Vector<UIntPtr>, Int32) Shifts each element of a vector left by the specified amount.
    int[] shiftCounts = new int[] { 1, elementBitSize - 1, elementBitSize, elementBitSize + 1, -1 };
    foreach (int shiftCount in shiftCounts) {
        if (typeof(T) == typeof(Byte)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorByte(srcT), shiftCount));
        } else if (typeof(T) == typeof(Int16)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorInt16(srcT), shiftCount));
        } else if (typeof(T) == typeof(Int32)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorInt32(srcT), shiftCount));
        } else if (typeof(T) == typeof(Int64)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorInt64(srcT), shiftCount));
        } else if (typeof(T) == typeof(IntPtr)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorNInt(srcT), shiftCount));
        } else if (typeof(T) == typeof(SByte)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorSByte(srcT), shiftCount));
        } else if (typeof(T) == typeof(UInt16)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorUInt16(srcT), shiftCount));
        } else if (typeof(T) == typeof(UInt32)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorUInt32(srcT), shiftCount));
        } else if (typeof(T) == typeof(UInt64)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorUInt64(srcT), shiftCount));
        } else if (typeof(T) == typeof(UIntPtr)) {
            WriteLineFormat(tw, indent, "ShiftLeft(srcT, " + shiftCount + "):\t{0}", Vector.ShiftLeft(Vector.AsVectorNUInt(srcT), shiftCount));
        }
    }
    

    2.5.3 out 引數

    有一些方法通過out 引數回傳了多個值,如能使資料變寬的 Widen,于是可利用“if塊”來限制不同型別變數的作用域,代碼如下,

    //Widen(Vector<Byte>, Vector<UInt16>, Vector<UInt16>) Widens aVector<Byte> into two Vector<UInt16>instances.
    //Widen(Vector<Int16>, Vector<Int32>, Vector<Int32>) Widens a Vector<Int16> into twoVector<Int32> instances.
    //Widen(Vector<Int32>, Vector<Int64>, Vector<Int64>) Widens a Vector<Int32> into twoVector<Int64> instances.
    //Widen(Vector<SByte>, Vector<Int16>, Vector<Int16>) Widens a Vector<SByte> into twoVector<Int16> instances.
    //Widen(Vector<Single>, Vector<Double>, Vector<Double>) Widens a Vector<Single> into twoVector<Double> instances.
    //Widen(Vector<UInt16>, Vector<UInt32>, Vector<UInt32>) Widens a Vector<UInt16> into twoVector<UInt32> instances.
    //Widen(Vector<UInt32>, Vector<UInt64>, Vector<UInt64>) Widens a Vector<UInt32> into twoVector<UInt64> instances.
    if (typeof(T) == typeof(Single)) {
        Vector<Double> low, high;
        Vector.Widen(Vector.AsVectorSingle(srcT), out low, out high);
        WriteLineFormat(tw, indent, "Widen(srcT).low:\t{0}", low);
        WriteLineFormat(tw, indent, "Widen(srcT).high:\t{0}", high);
    } else if (typeof(T) == typeof(SByte)) {
        Vector<Int16> low, high;
        Vector.Widen(Vector.AsVectorSByte(srcT), out low, out high);
        WriteLineFormat(tw, indent, "Widen(srcT).low:\t{0}", low);
        WriteLineFormat(tw, indent, "Widen(srcT).high:\t{0}", high);
    } else if (typeof(T) == typeof(Int16)) {
        Vector<Int32> low, high;
        Vector.Widen(Vector.AsVectorInt16(srcT), out low, out high);
        WriteLineFormat(tw, indent, "Widen(srcT).low:\t{0}", low);
        WriteLineFormat(tw, indent, "Widen(srcT).high:\t{0}", high);
    } else if (typeof(T) == typeof(Int32)) {
        Vector<Int64> low, high;
        Vector.Widen(Vector.AsVectorInt32(srcT), out low, out high);
        WriteLineFormat(tw, indent, "Widen(srcT).low:\t{0}", low);
        WriteLineFormat(tw, indent, "Widen(srcT).high:\t{0}", high);
    } else if (typeof(T) == typeof(Byte)) {
        Vector<UInt16> low, high;
        Vector.Widen(Vector.AsVectorByte(srcT), out low, out high);
        WriteLineFormat(tw, indent, "Widen(srcT).low:\t{0}", low);
        WriteLineFormat(tw, indent, "Widen(srcT).high:\t{0}", high);
    } else if (typeof(T) == typeof(UInt16)) {
        Vector<UInt32> low, high;
        Vector.Widen(Vector.AsVectorUInt16(srcT), out low, out high);
        WriteLineFormat(tw, indent, "Widen(srcT).low:\t{0}", low);
        WriteLineFormat(tw, indent, "Widen(srcT).high:\t{0}", high);
    } else if (typeof(T) == typeof(UInt32)) {
        Vector<UInt64> low, high;
        Vector.Widen(Vector.AsVectorUInt32(srcT), out low, out high);
        WriteLineFormat(tw, indent, "Widen(srcT).low:\t{0}", low);
        WriteLineFormat(tw, indent, "Widen(srcT).high:\t{0}", high);
    }
    

    2.6 格式化輸出(WriteLineFormat)

    雖然只讀結構體 Vector<T>支持 ToString,能夠輸出各個元素的數值,但在很多時候(例如使用 AndNot 的函式進行二進制運算時),我們需要觀察它的二進制資料,故需要以十六進制的方式來顯示其中的資料,但Vector<T>不支持十六進制格式化(X),
    于是專門為 Vector<T> 寫了一個多載函式,用于輸出它的十六進制值,

    /// <summary>
    /// Get hex string.
    /// </summary>
    /// <typeparam name="T">Vector value type.</typeparam>
    /// <param name="src">Source value.</param>
    /// <param name="separator">The separator.</param>
    /// <param name="noFixEndian">No fix endian.</param>
    /// <returns>Returns hex string.</returns>
    private static string GetHex<T>(Vector<T> src, string separator, bool noFixEndian) where T : struct {
        Vector<byte> list = Vector.AsVectorByte(src);
        int unitCount = Vector<T>.Count;
        int unitSize = Vector<byte>.Count / unitCount;
        bool fixEndian = false;
        if (!noFixEndian && BitConverter.IsLittleEndian) fixEndian = true;
        StringBuilder sb = new StringBuilder();
        if (fixEndian) {
            // IsLittleEndian.
            for (int i=0; i < unitCount; ++i) {
                if ((i > 0)) {
                    if (!string.IsNullOrEmpty(separator)) {
                        sb.Append(separator);
                    }
                }
                int idx = unitSize * (i+1) - 1;
                for(int j = 0; j < unitSize; ++j) {
                    byte by = list[idx];
                    --idx;
                    sb.Append(by.ToString("X2"));
                }
            }
        } else {
            for (int i = 0; i < Vector<byte>.Count; ++i) {
                byte by = list[i];
                if ((i > 0) && (0 == i % unitSize)) {
                    if (!string.IsNullOrEmpty(separator)) {
                        sb.Append(separator);
                    }
                }
                sb.Append(by.ToString("X2"));
            }
        }
        return sb.ToString();
    }
    
    /// <summary>
    /// WriteLine with format.
    /// </summary>
    /// <typeparam name="T">Vector value type.</typeparam>
    /// <param name="tw">The TextWriter.</param>
    /// <param name="indent">The indent.</param>
    /// <param name="format">The format.</param>
    /// <param name="src">Source value</param>
    private static void WriteLineFormat<T>(TextWriter tw, string indent, string format, Vector<T> src) where T : struct {
        if (null == tw) return;
        string line = indent + string.Format(format, src);
        string hex = GetHex(src, " ", false);
        line += "\t# (" + hex +")";
        tw.WriteLine(line);
    }
    

    三、運行結果

    由于Vector類提供了大量的向量方法,再乘以10種基元型別,導致本程式的輸出資訊很長,達到了90多KB,
    為了避免文章過長,于是這里僅摘錄了主要的輸出資訊,

    VectorClassDemo50
    
    IsRelease:	False
    EnvironmentVariable(PROCESSOR_IDENTIFIER):	Intel64 Family 6 Model 142 Stepping 10, GenuineIntel
    Environment.ProcessorCount:	8
    Environment.Is64BitOperatingSystem:	True
    Environment.Is64BitProcess:	True
    Environment.OSVersion:	Microsoft Windows NT 10.0.19044.0
    Environment.Version:	7.0.0
    RuntimeEnvironment.GetRuntimeDirectory:	C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.0\
    RuntimeInformation.FrameworkDescription:	.NET 7.0.0
    BitConverter.IsLittleEndian:	True
    IntPtr.Size:	8
    Vector.IsHardwareAccelerated:	True
    Vector<byte>.Count:	32	# 256bit
    Vector<T>.Assembly.CodeBase:	file:///C:/Program Files/dotnet/shared/Microsoft.NETCore.App/7.0.0/System.Private.CoreLib.dll
    
    [Intrinsics.X86]
    Aes.IsSupported:	True
    Aes.X64.IsSupported:	True
    Avx.IsSupported:	True
    Avx.X64.IsSupported:	True
    Avx2.IsSupported:	True
    Avx2.X64.IsSupported:	True
    AvxVnni.IsSupported:	False
    AvxVnni.X64.IsSupported:	False
    Bmi1.IsSupported:	True
    Bmi1.X64.IsSupported:	True
    Bmi2.IsSupported:	True
    Bmi2.X64.IsSupported:	True
    Fma.IsSupported:	True
    Fma.X64.IsSupported:	True
    Lzcnt.IsSupported:	True
    Lzcnt.X64.IsSupported:	True
    Pclmulqdq.IsSupported:	True
    Pclmulqdq.X64.IsSupported:	True
    Popcnt.IsSupported:	True
    Popcnt.X64.IsSupported:	True
    Sse.IsSupported:	True
    Sse.X64.IsSupported:	True
    Sse2.IsSupported:	True
    Sse2.X64.IsSupported:	True
    Sse3.IsSupported:	True
    Sse3.X64.IsSupported:	True
    Sse41.IsSupported:	True
    Sse41.X64.IsSupported:	True
    Sse42.IsSupported:	True
    Sse42.X64.IsSupported:	True
    Ssse3.IsSupported:	True
    Ssse3.X64.IsSupported:	True
    X86Base.IsSupported:	True
    X86Base.X64.IsSupported:	True
    X86Serialize.IsSupported:	False
    X86Serialize.X64.IsSupported:	False
    
    [Intrinsics.Arm]
    AdvSimd.IsSupported:	False
    AdvSimd.Arm64.IsSupported:	False
    Aes.IsSupported:	False
    Aes.Arm64.IsSupported:	False
    ArmBase.IsSupported:	False
    ArmBase.Arm64.IsSupported:	False
    Crc32.IsSupported:	False
    Crc32.Arm64.IsSupported:	False
    Dp.IsSupported:	False
    Dp.Arm64.IsSupported:	False
    Rdm.IsSupported:	False
    Rdm.Arm64.IsSupported:	False
    Sha1.IsSupported:	False
    Sha1.Arm64.IsSupported:	False
    Sha256.IsSupported:	False
    Sha256.Arm64.IsSupported:	False
    
    -- Single, Vector<Single>.Count=8 --
    srcT:	<-3.4028235E+38, ∞, NaN, -1.2, 0, 1, 2, 4>	# (FF7FFFFF 7F800000 FFC00000 BF99999A 00000000 3F800000 40000000 40800000)
    srcAllOnes:	<NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN>	# (FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF)
    Abs(srcT):	<3.4028235E+38, ∞, NaN, 1.2, 0, 1, 2, 4>	# (7F7FFFFF 7F800000 7FC00000 3F99999A 00000000 3F800000 40000000 40800000)
    Abs(srcAllOnes):	<NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN>	# (7FFFFFFF 7FFFFFFF 7FFFFFFF 7FFFFFFF 7FFFFFFF 7FFFFFFF 7FFFFFFF 7FFFFFFF)
    Add(srcT, src1):	<-3.4028235E+38, ∞, NaN, -0.20000005, 1, 2, 3, 5>	# (FF7FFFFF 7F800000 FFC00000 BE4CCCD0 3F800000 40000000 40400000 40A00000)
    Add(srcT, src2):	<-3.4028235E+38, ∞, NaN, 0.79999995, 2, 3, 4, 6>	# (FF7FFFFF 7F800000 FFC00000 3F4CCCCC 40000000 40400000 40800000 40C00000)
    AndNot(srcT, src1):	<-3.9999998, 2, -3, -2.350989E-39, 0, 0, 2, 2>	# (C07FFFFF 40000000 C0400000 8019999A 00000000 00000000 40000000 40000000)
    AndNot(srcT, src2):	<-0.99999994, 1, -1.5, -1.2, 0, 1, 0, 1.1754944E-38>	# (BF7FFFFF 3F800000 BFC00000 BF99999A 00000000 3F800000 00000000 00800000)
    BitwiseAnd(srcT, src1):	<0.5, 1, 1, 1, 0, 1, 0, 1.1754944E-38>	# (3F000000 3F800000 3F800000 3F800000 00000000 3F800000 00000000 00800000)
    BitwiseAnd(srcT, src2):	<2, 2, 2, 0, 0, 0, 2, 2>	# (40000000 40000000 40000000 00000000 00000000 00000000 40000000 40000000)
    BitwiseOr(srcT, src1):	<NaN, ∞, NaN, -1.2, 1, 1, ∞, ∞>	# (FFFFFFFF 7F800000 FFC00000 BF99999A 3F800000 3F800000 7F800000 7F800000)
    BitwiseOr(srcT, src2):	<-3.4028235E+38, ∞, NaN, NaN, 2, ∞, 2, 4>	# (FF7FFFFF 7F800000 FFC00000 FF99999A 40000000 7F800000 40000000 40800000)
    ...
    Widen(srcT).low:	<-3.4028234663852886E+38, ∞, NaN, -1.2000000476837158>	# (C7EFFFFFE0000000 7FF0000000000000 FFF8000000000000 BFF3333340000000)
    Widen(srcT).high:	<0, 1, 2, 4>	# (0000000000000000 3FF0000000000000 4000000000000000 4010000000000000)
    ...
    
    -- Double, Vector<Double>.Count=4 --
    srcT:	<-1.7976931348623157E+308, ∞, -1.2, 0>	# (FFEFFFFFFFFFFFFF 7FF0000000000000 BFF3333333333333 0000000000000000)
    srcAllOnes:	<NaN, NaN, NaN, NaN>	# (FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF)
    Abs(srcT):	<1.7976931348623157E+308, ∞, 1.2, 0>	# (7FEFFFFFFFFFFFFF 7FF0000000000000 3FF3333333333333 0000000000000000)
    Abs(srcAllOnes):	<NaN, NaN, NaN, NaN>	# (7FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF)
    Add(srcT, src1):	<-1.7976931348623157E+308, ∞, -0.19999999999999996, 1>	# (FFEFFFFFFFFFFFFF 7FF0000000000000 BFC9999999999998 3FF0000000000000)
    Add(srcT, src2):	<-1.7976931348623157E+308, ∞, 0.8, 2>	# (FFEFFFFFFFFFFFFF 7FF0000000000000 3FE999999999999A 4000000000000000)
    AndNot(srcT, src1):	<-3.9999999999999996, 2, -4.4501477170144E-309, 0>	# (C00FFFFFFFFFFFFF 4000000000000000 8003333333333333 0000000000000000)
    AndNot(srcT, src2):	<-0.9999999999999999, 1, -1.2, 0>	# (BFEFFFFFFFFFFFFF 3FF0000000000000 BFF3333333333333 0000000000000000)
    BitwiseAnd(srcT, src1):	<0.5, 1, 1, 0>	# (3FE0000000000000 3FF0000000000000 3FF0000000000000 0000000000000000)
    BitwiseAnd(srcT, src2):	<2, 2, 0, 0>	# (4000000000000000 4000000000000000 0000000000000000 0000000000000000)
    BitwiseOr(srcT, src1):	<NaN, ∞, -1.2, 1>	# (FFFFFFFFFFFFFFFF 7FF0000000000000 BFF3333333333333 3FF0000000000000)
    BitwiseOr(srcT, src2):	<-1.7976931348623157E+308, ∞, NaN, 2>	# (FFEFFFFFFFFFFFFF 7FF0000000000000 FFF3333333333333 4000000000000000)
    ...
    
    -- UInt64, Vector<UInt64>.Count=4 --
    srcT:	<0, 18446744073709551615, 0, 1>	# (0000000000000000 FFFFFFFFFFFFFFFF 0000000000000000 0000000000000001)
    srcAllOnes:	<18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615>	# (FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF)
    Abs(srcT):	<0, 18446744073709551615, 0, 1>	# (0000000000000000 FFFFFFFFFFFFFFFF 0000000000000000 0000000000000001)
    Abs(srcAllOnes):	<18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615>	# (FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF)
    Add(srcT, src1):	<1, 0, 1, 2>	# (0000000000000001 0000000000000000 0000000000000001 0000000000000002)
    Add(srcT, src2):	<2, 1, 2, 3>	# (0000000000000002 0000000000000001 0000000000000002 0000000000000003)
    AndNot(srcT, src1):	<0, 18446744073709551614, 0, 0>	# (0000000000000000 FFFFFFFFFFFFFFFE 0000000000000000 0000000000000000)
    AndNot(srcT, src2):	<0, 18446744073709551613, 0, 1>	# (0000000000000000 FFFFFFFFFFFFFFFD 0000000000000000 0000000000000001)
    BitwiseAnd(srcT, src1):	<0, 1, 0, 1>	# (0000000000000000 0000000000000001 0000000000000000 0000000000000001)
    BitwiseAnd(srcT, src2):	<0, 2, 0, 0>	# (0000000000000000 0000000000000002 0000000000000000 0000000000000000)
    BitwiseOr(srcT, src1):	<1, 18446744073709551615, 1, 1>	# (0000000000000001 FFFFFFFFFFFFFFFF 0000000000000001 0000000000000001)
    BitwiseOr(srcT, src2):	<2, 18446744073709551615, 2, 3>	# (0000000000000002 FFFFFFFFFFFFFFFF 0000000000000002 0000000000000003)
    ...
    ShiftLeft(srcT, 1):	<0, 18446744073709551614, 0, 2>	# (0000000000000000 FFFFFFFFFFFFFFFE 0000000000000000 0000000000000002)
    ShiftLeft(srcT, 63):	<0, 9223372036854775808, 0, 9223372036854775808>	# (0000000000000000 8000000000000000 0000000000000000 8000000000000000)
    ShiftLeft(srcT, 64):	<0, 18446744073709551615, 0, 1>	# (0000000000000000 FFFFFFFFFFFFFFFF 0000000000000000 0000000000000001)
    ShiftLeft(srcT, 65):	<0, 18446744073709551614, 0, 2>	# (0000000000000000 FFFFFFFFFFFFFFFE 0000000000000000 0000000000000002)
    ShiftLeft(srcT, -1):	<0, 9223372036854775808, 0, 9223372036854775808>	# (0000000000000000 8000000000000000 0000000000000000 8000000000000000)
    

    完整的測驗結果,請運行程式進行查看,
    原始碼地址——
    https://github.com/zyl910/BenchmarkVector/tree/main/VectorClassDemo

    參考文獻

    • MSDN《Vector<T> 結構》. https://docs.microsoft.com/zh-cn/dotnet/api/system.numerics.vector-1?view=netcore-1.0
    • MSDN《Vector 類》. https://docs.microsoft.com/zh-cn/dotnet/api/system.numerics.vector?view=netcore-1.0
    • Nuget《System.Numerics.Vectors》. https://www.nuget.org/packages/System.Numerics.Vectors
    • Intel《Intel? Intrinsics Guide》. https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html
    • zyl910《C# 使用SIMD向量型別加速浮點陣列求和運算(1):使用Vector4、Vector<T>》. https://www.cnblogs.com/zyl910/p/dotnet_simd_BenchmarkVector1.html
    • zyl910《C#利用條件編譯判斷.NET平臺及版本的辦法,NET5標準符號清單及使用經驗》. https://www.cnblogs.com/zyl910/p/cs_standard_conditional_compilation_symbols.html
    作者:zyl910 出處:http://www.cnblogs.com/zyl910/ 著作權宣告:自由轉載-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0.

    轉載請註明出處,本文鏈接:https://www.uj5u.com/net/536721.html

    標籤:C#

    上一篇:學習ASP.NET Core Blazor編程系列十——路由(下)

    下一篇:篇(16)-Asp.Net Core入門實戰-權限管理之用戶創建與關聯角色(ViewModel再用與模型驗證二)

    標籤雲
    其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

    熱門瀏覽
    • WebAPI簡介

      Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

      uj5u.com 2020-09-09 22:07:47 more
    • asp.net core 3.1 入口:Program.cs中的Main函式

      本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

      uj5u.com 2020-09-09 22:07:49 more
    • asp.net網站作為websocket服務端的應用該如何寫

      最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

      uj5u.com 2020-09-09 22:08:02 more
    • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

      Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

      uj5u.com 2020-09-09 22:08:05 more
    • 在webform中使用ajax

      如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

      uj5u.com 2020-09-09 22:08:50 more
    • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

      今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

      uj5u.com 2020-09-09 22:10:00 more
    • WebAPI-處理架構

      帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

      uj5u.com 2020-09-09 22:11:13 more
    • 微信門戶開發框架-使用指導說明書

      微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

      uj5u.com 2020-09-09 22:15:18 more
    • WebAPI-HTTP編程模型

      帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

      uj5u.com 2020-09-09 22:15:23 more
    • 部署WebApi隨筆

      一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

      uj5u.com 2020-09-09 22:15:48 more
    最新发布
    • C#多執行緒學習(二) 如何操縱一個執行緒

      <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

      uj5u.com 2023-04-19 09:17:20 more
    • C#多執行緒學習(二) 如何操縱一個執行緒

      C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

      uj5u.com 2023-04-19 09:16:49 more
    • 記一次 .NET某醫療器械清洗系統 卡死分析

      <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

      uj5u.com 2023-04-18 08:39:04 more
    • 記一次 .NET某醫療器械清洗系統 卡死分析

      一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

      uj5u.com 2023-04-18 08:33:10 more
    • SignalR, No Connection with that ID,IIS

      <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

      uj5u.com 2023-03-30 17:21:52 more
    • 一次對pool的誤用導致的.net頻繁gc的診斷分析

      <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

      uj5u.com 2023-03-28 10:15:33 more
    • 一次對pool的誤用導致的.net頻繁gc的診斷分析

      <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

      uj5u.com 2023-03-28 10:13:31 more
    • C#遍歷指定檔案夾中所有檔案的3種方法

      <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

      uj5u.com 2023-03-27 14:46:55 more
    • C#/VB.NET:如何將PDF轉為PDF/A

      <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

      uj5u.com 2023-03-27 14:46:35 more
    • 武裝你的WEBAPI-OData聚合查詢

      <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

      uj5u.com 2023-03-27 14:46:16 more