[譯] .NET 8 中的硬體內在函數(支持 Wasm 和 AVX-512)

来源:https://www.cnblogs.com/zyl910/p/18133514/dotnet-8-hardware-intrinsics
-Advertisement-
Play Games

老周在幾個世紀前曾寫過樹莓派相關的 iOT 水文,之所以沒寫 Nano Framework 相關的內容,是因為那時候這貨還不成熟,可玩性不高。不過,這貨現在已經相對完善,老周都把它用在項目上了——第一個是自製的智能插座,這個某寶上50多塊可以買到,搜“esp32 插座”就能找到。一種是 86 型盒子 ...


原文鏈接:
https://devblogs.microsoft.com/dotnet/dotnet-8-hardware-intrinsics/
Hardware Intrinsics in .NET 8
Tanner Gooding [MSFT]
December 11th, 2023

譯文:

.NET 8 中的硬體內在函數 坦納·古丁 [MSFT] 2023年12月11日

.NET在通過JIT編譯器本質上理解的API提供對附加硬體功能的訪問方面有著悠久的歷史。這始於2014年的.NET Framework,並隨著2019年.NET Core 3.0的引入而擴展。從那時起,運行時迭代地提供了更多的API,併在每個版本中更好地利用了這一點。

簡要概述如下:

  • 2014年- .NET 4.5.2 -第一批在 System.Numerics 命名空間中公開的 API
    • 介紹Vector<T>
    • 引入Vector2Vector3Vector4Matrix4x4QuaternionPlane
    • 64-僅位
    • 另請參閱:https://devblogs.microsoft.com/dotnet/the-jit-finally-proposed-jit-and-simd-are-getting-married/
  • 2019年- .NET Core 3.0 -第一批在 System.Runtime.Intrinsics 命名空間中公開的 API
    • 介紹Vector128<T>Vector256<T>
    • x86和x64引入Sse、Sse2、Sse3Ssse3Sse41Sse42AvxAvx2FmaBmi1Bmi2LzcntPopcntAesPclmul
    • 32-位和64位支持
    • 另請參閱:https://devblogs.microsoft.com/dotnet/hardware-intrinsics-in-net-core/
  • 2020年- .NET 5 -  System.Runtime.Intrinsics 命名空間中添加了 Arm 支持
    • 介紹Vector64<T>
    • Arm/Arm64引入AdvSimd、ArmBase、DpRdmAesCrc32Sha1Sha256
    • X86Base/x86引入x64
    • 另請參閱:https://devblogs.microsoft.com/dotnet/announcing-net-5-0-preview-7/
  • 2021 - .NET 6 - Codegen和基礎設施改進
    • x86/x64引入AvxVnni
    • 重寫System.Numerics實現以使用System.Runtime.Intrinsics
    • 另請參閱:https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/
  • 2022 - .NET 7 -支持編寫跨平臺演算法
    • 在跨平臺工作的Vector64<T>Vector128<T>Vector256<T>類型上引入了重要的新功能
    • x86/x64引入X86Serialize
    • 使上述向量類型和Vector<T>公開的API界面具有奇偶性
    • 另請參閱:https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/
  • 2023 - .NET 8 - 支持 wasm 和AVX-512
    • Wasm引入PackedSimd和WasmBase
    • 介紹Vector512<T>
    • x86/x64引入Avx512F、Avx512BW、Avx512CDAvx512DQAvx512Vbmi
    • 另請參閱:此博客文章的其餘部分

由於這項工作,每個版本的.NET庫和應用程式都獲得了更多的能力來利用底層硬體。在這篇文章中,我將深入介紹我們在.NET 8中引入的內容以及它所支持的功能類型。

WebAssembly支持

WebAssembly,簡稱Wasm,本質上是在瀏覽器中運行的代碼,它允許比典型的解釋型腳本支持更高的性能配置文件。作為一個平臺,Wasm已經開始提供底層SIMD(單指令,多數據)支持,以便可以加速核心演算法,.NET相應地選擇通過硬體內部函數公開對此功能的支持。

這種支持與其他平臺提供的基礎非常相似,因此我們不會詳細介紹。相反,您可以簡單地期望使用Vector128<T>的現有跨平臺演算法將隱式地照亮支持的地方。如果您想更直接地利用Wasm獨有的功能,那麼您可以顯式地使用PackedSimd命名空間中的WasmBaseSystem.Runtime.Intrinsics.Wasm類公開的API。

AVX-512支持

AVX-512是為x86和x64電腦提供的新功能集。它帶來了沿著的大量新指令和硬體功能,包括支持16個額外的SIMD寄存器,專用掩碼,以及一次操作512位數據。訪問此功能需要一個相對較新的處理器,即需要英特爾的Skylake-X或更新版本,以及AMD的Zen 4或更新版本。因此,可以利用此新功能的用戶數量較少,但它可以為硬體帶來的改進仍然很重要,並且值得支持數據繁重的工作負載。此外,JIT將在其確定存在益處的情況下針對現有SIMD代碼機會性地利用這些指令。一些例子包括:

  • 當完成按位條件選擇時使用vpternlog而不是and, andn, orVector128.ConditionalSelect
  • 使用EVEX編碼將更多操作放入更少的代碼位元組中,例如用於嵌入式廣播(x + Vector128.Create(5)
  • 使用更新的指令,其中支持AVX-512,例如全寬度混洗和許多long/ulongInt64/UInt64)操作
  • 還有其他的改進,這裡沒有列出,你可以期待隨著時間的推移會有更多的改進。
    • 某些情況下,例如Vector<T>允許擴展到512位,在.NET 8中沒有完成

為了支持512位的新向量大小,.NET引入了Vector512<T>類型。這公開了與其他固定大小的向量類型(如Vector256<T>)相同的通用API錶面。它同樣繼續暴露Vector512.IsHardwareAccelerated屬性,該屬性允許您確定是否應該在硬體中加速通用邏輯,或者是否最終通過軟體回退來模擬行為。

Vector 512在Ice Lake和更新的硬體上預設使用AVX-512加速(因此Vector512.IsHardwareAccelerated報告true),其中AVX-512指令不會導致CPU顯著降頻;而使用AVX-512指令會導致Skylake-X,Cascade Lake和庫珀Lake硬體上更顯著的降頻(另請參見2.5.3 Skylake Server Power Management中的Intel® 64 and IA-32 Architectures Optimization Reference Manual: Volume 1)。雖然這最終有利於大型工作負載,但它可能會對其他較小的工作負載產生負面影響,因此我們預設在這些平臺上報告falseVector512.IsHardwareAcceleratedAvx512F.IsSupported仍然會報告true,如果直接調用,Vector512的底層實現仍然會使用AVX-512指令。這允許工作負載利用他們知道的功能,而不會意外地對其他人造成負面影響。

特別感謝

這一功能的實現得益於我們在英特爾的朋友們的巨大貢獻。多年來,.NET團隊和英特爾已經進行了多次合作,我們繼續在整體設計和實現方面進行合作,從而使AVX-512支持登陸.NET 8。

還有來自.NET社區的大量輸入和驗證,幫助實現了成功並使發佈變得更好。

如果您想貢獻或提供輸入,請加入我們在GitHub上的dotnet/runtimerepos,並按照我們的時間表.NET Foundation YouTube頻道上收聽API Review,您可以看到我們討論.NET庫的新添加,甚至通過聊天頻道提供您自己的輸入。

不只是512位?

與名稱相反,AVX-512不僅僅是512位支持。額外的寄存器、掩碼支持、嵌入式舍入或廣播支持以及新指令也都適用於128位和256位向量。這意味著您現有的工作負載可以隱式地變得更好,並且您可以顯式地利用新功能,而這種隱式的點亮是不可能的。

當SSE於1999年在Intel Pentium III上首次引入時,它提供了8個寄存器,每個寄存器長度為128位。這些寄存器被稱為xmm0xmm7。當x64平臺後來於2003年在AMD Athlon 64上推出時,它提供了8個額外的寄存器,可以訪問64位代碼。這些寄存器被命名為xmm8xmm15。這種初始支持使用了一種簡單的編碼方案,其工作方式與通用指令非常相似,只允許指定2個寄存器。對於需要2個輸入的加法,這意味著其中一個寄存器既充當輸入又充當輸出。這意味著如果你的輸入和輸出需要不同,你需要2條指令來完成操作。z = x + y會變成z = x; z += y。在高級別上,這些行為是相同的,但在低級別上,有兩個步驟而不是一個步驟來實現它。

2011年,英特爾在基於桑迪橋的處理器上推出了AVX,將支持擴展到256位,從而進一步擴展了這一點。這些較新的寄存器被命名為ymm0ymm15,只有直到ymm7的寄存器才能訪問32位代碼。這也引入了一種稱為VEX(矢量擴展)的新編碼,允許對3個寄存器進行編碼。這意味著您可以直接編碼z = x + y,而不必將其分為兩個單獨的步驟。

AVX-512隨後由英特爾於2017年推出,採用基於Skylake-X的處理器。這將支持擴展到512位,並將寄存器命名為zmm0zmm15。它還引入了16個新寄存器,恰當地命名為zmm16zmm31,並且還有xmm16-xmm31ymm16-ymm31變體。與前面的情況一樣,只有zmm7以下的寄存器才能訪問32位代碼。它引入了8個新的寄存器,命名為k0k7,旨在支持“掩碼”和另一種名為EVEX(增強型矢量擴展)的新編碼,允許表達所有這些新信息。EVEX編碼還具有允許以更緊湊的方式表達更常見的信息和操作的其他特征。這可以幫助減少代碼大小,同時提高性能。

有哪些新的指示?

有很多新功能,太多了,無法在這篇博客文章中涵蓋所有內容。但一些最值得註意的新指令提供了以下內容:

  • 支持對64位整數進行AbsMaxMin和移位等操作-以前必須使用多條指令來模擬此功能
  • 支持在無符號整數和浮點類型之間進行轉換
  • 支持使用浮點邊緣情況
  • 支持在一個或多個向量中完全重新排列元素
  • 支持在單個指令中執行2個按位操作

64位整數支持是值得註意的,因為這意味著處理64位數據不需要使用較慢或替代的代碼序列來支持相同的功能。這使得編寫代碼並期望其行為相同變得更加容易,而不管您正在使用的底層數據類型如何。

浮點數到無符號整數轉換的支持也是出於類似的原因。從double轉換到long需要一條指令,但是從double轉換到ulong需要很多指令。使用AVX-512,這變成了一條指令,允許用戶在處理無符號數據時獲得預期的性能。這在各種圖像處理或機器學習場景中很常見。

對浮點數據的擴展支持是我最喜歡的AVX-512特性之一。一些示例包括提取無偏指數(Avx512F.GetExponent)或歸一化尾數(Avx512F.GetMantissa)、將浮點值舍入為特定小數位數(Avx512F.RoundScale)、將值乘以2^x(Avx512F.Scale,在C中稱為scalebn),以正確處理MinMaxMinMagnitude)來執行MaxMagnitude+0-0Avx512DQ.Range,甚至可以進行簡化,這在處理像SinCosAvx512DQ.Reduce)這樣的三角函數的大值時是有用的。

然而,我個人最喜歡的指令之一是名為vfixupimmAvx512F.Fixup)的指令。在高級別上,此指令允許您檢測許多輸入邊緣情況,並將輸出“修複”為常見輸出之一,並按元素執行此操作。這可以大大提高某些演算法的性能,並大大減少所需的處理量。它的工作方式是它需要4個輸入,即leftrighttablecontrol。它首先對right中的浮點值進行分類,並確定它是QNaN(0)、SNaN(1)、+/-0(2)、+1(3)、-Infinity(4)、+Infinity(5)、Negative(6)還是Positive(7)。然後,它使用它從4讀取table位(QNaN0,讀取位0..3;Negative6讀取位24..27)。table中這4位的值決定了結果。可能的結果(每個元素)是:

位模式 定義
0b0000 左[i]
0b0001 右[i]
0b0010 QNaN(右[i])
0b0011 QNaN
0b0100 -Infinity
0b0101 +Infinity
0b0110 IsNegative(right[i])?-Infinity:+Infinity
0b0111 -0.0
0b1000 +0.0
0b1001 -1.0
0b1010 +1.0
0b1011 +0.5
0b1100 +90.0
0b1101 Pi / 2
0b1110 MaxValue
0b1111 MinValue

在SSE中,有一些支持在向量中重新排列數據。例如,你有0, 1, 2, 3,你想訂購3, 1, 2, 0。隨著AVX的引入和擴展到256位,這種支持也得到了擴展。然而,由於指令的操作方式,你實際上會執行兩次相同的128位操作。這使得將現有演算法擴展到256位變得簡單,因為你實際上只是做了兩次同樣的事情。然而,當你實際上需要考慮整個向量時,它使使用其他演算法變得更加困難。有一些指令可以讓你在整個256位向量中重新排列數據,但它們通常在數據如何重新排列或它們支持的類型方面受到限制(位元組元素的完全洗牌是缺少支持的一個明顯例子)。AVX-512對於其擴展的512位支持有許多相同的考慮。但是,它還引入了新的指令來填充差距,現在可以讓您完全重新排列任何大小的元素的元素。

最後,我個人最喜歡的指令之一是名為vpternlogAvx512F.TernaryLogic)的指令。此指令允許您採用任何2個按位操作並將它們聯合收割機組合,因此它們可以在單個指令中執行。例如,您可以執行(a & b) | c。它的工作方式是它需要4個輸入,abccontrol。然後你有三個鍵要記住:A: 0xF0B: 0xCCC: 0xAA。為了表示所需的操作,您只需通過對這些鍵執行該操作來構建control。所以,如果你想簡單地返回a,你可以使用0xF0。如果你想做a & b,你會使用(byte)(0xF0 & 0xCC)。如果你想做(a & b) | c,那麼它就是(byte)((0xF0 & 0xCC) | 0xAA。總共有256種不同的操作,基本的構建塊是那些鍵和以下按位操作:

操作 定義
not ~x
and X & Y
nand ~x & y
or X
nor ~x
xor X ^ y
xnor ~x ^ y

然後還有一些特殊的操作,也支持上述基本操作,並且可以進一步擴展。

操作 定義
位模式為0x00
0xFF的位模式
主要 如果兩個或多個輸入位為0,則返回0;如果兩個或多個輸入位為1,則返回1
次要 如果兩個或多個輸入位為1,則返回0;如果兩個或多個輸入位為0,則返回1
條件選擇 邏輯上是(x & y) | (~x & z),因為它是(x and y) or (x nand y)

在.NET 8中,我們沒有完成對隱式識別和摺疊這些模式以發出vpternlog的支持。我們希望它在.NET 9中首次亮相。

什麼是屏蔽支持?

在最簡單的級別上,編寫向量化代碼涉及使用SIMD在單個指令中對類型CountT不同元素執行相同的基本操作。當需要對所有數據執行相同的操作時,這非常有效。然而,並非所有數據都是統一的,有時您需要以不同的方式處理特定的輸入。例如,您可能希望對正數和負數執行不同的操作。如果用戶傳入了NaN,你可能需要返回一個不同的結果,等等。在編寫常規代碼時,你通常會用一個分支來處理這個問題,這工作得很好。但是,在編寫向量化代碼時,這樣的分支會破壞使用SIMD指令的能力,因為您必須獨立處理每個元素。.NET在不同的地方利用了這一點,包括新的TensorPrimitivesAPI,它允許我們處理不適合完整向量的尾隨數據。

典型的解決方案是編寫“無分支”代碼。最簡單的方法之一是計算兩個答案,然後使用按位運算來選擇正確的答案。你可以把它想象成一個三元條件cond ? result1 : result2。為了在SIMD中支持這一點,存在一個名為ConditionalSelect的API,它接受一個掩碼和兩個結果。掩碼也是一個向量,但其值通常為AllBitsSetZero。當你有了這個模式,那麼ConditionalSelect的實現實際上就是(cond & result1) | (~cond & result2)。這分解為從result1中取出位,其中cond中的對應位是1,否則從result2中取出對應位(當cond中的位是0時)。因此,如果你想將所有負值轉換為0,那麼對於常規代碼,你會得到類似於(x < 0) ? 0 : x的值,而對於矢量化代碼,你會得到類似於Vector128.ConditionalSelect(Vector128.LessThan(x, Vector128.Zero), Vector128.Zero, x)的值。它有點冗長,但也可以提供顯著的性能改進。

當硬體第一次開始支持SIMD時,您必須通過執行3條指令來支持這種掩碼:and, nand, or。隨著新硬體的出現,添加了更多優化版本,允許您在單個指令中執行此操作,例如x86/x64上的blendv和Arm 64上的bsl。AVX-512則進一步引入了專用硬體支持來表達掩碼併在寄存器中跟蹤它們(前面提到的k0-k7)。然後,它提供了額外的支持,允許這種掩蔽作為幾乎任何其他操作的一部分來完成。因此,不必指定vcmpltps; vblendvps; vaddps(比較,掩碼,然後添加),您可以直接將掩碼編碼為加法的一部分(從而發出vcmpltps; vaddps)。這允許硬體在更少的空間中表示更多的操作,提高代碼密度,並更好地利用預期的行為。

值得註意的是,我們在這裡沒有直接公開與底層硬體的1對1概念。相反,JIT繼續獲取並返回用於比較結果的常規向量,並基於此進行相關的模式識別和掩蔽特征的後續機會光照。這允許暴露的API錶面顯著更小(減少超過3000個API),現有代碼在很大程度上“只是工作”並利用較新的硬體支持而無需顯式操作,並且希望支持AVX-512的用戶不必學習新概念或以新方式編寫代碼。

AVX-512在實踐中的使用示例如何?

AVX-512可用於加速所有與SSE或AVX相同的場景。識別.NET庫已經使用這種加速的一種簡單方法是搜索我們稱之為Vector512.IsHardwareAccelerated的地方

我們加速了以下案例:

在.NET庫和一般的.NET生態系統中還有其他例子,太多了,無法列出和覆蓋。這些包括但不限於顏色轉換、圖像處理、機器學習、文本轉碼、JSON解析、軟體渲染、光線跟蹤、游戲加速等場景。

接下來呢?

我們計劃繼續改進.NET中的硬體內部支持,無論何時何地。請註意,以下項目是前瞻性的思考和推測。該列表是不完整的,我們不提供任何這些功能將土地或當他們將船舶,如果他們這樣做。

我們長期路線圖中的一些項目包括以下內容:

  • Arm64的SVE和SVE 2
  • x86/x64的AVX10
  • 允許Vector<T>隱式擴展到512位
  • ISimdVector<TSelf, T>介面,允許更好地重用SIMD邏輯
  • 一個分析器,幫助鼓勵用戶使用語義相同的跨平臺API(使用x + y而不是Sse.Add(x, y)
  • 一個分析器,用於識別可能具有更優替代方案的模式(執行value + value而不是value * 2Sse.UnpackHigh(value, value)而不是Sse.Shuffle(value, value, 0b11_11_10_10)
  • 在各種.NET API中額外顯式使用硬體內部函數
  • 額外的跨平臺API,幫助抽象通用操作
    • 獲取掩碼中第一個/最後一個匹配項的索引
    • 獲取掩碼中的匹配數
    • 確定是否存在任何匹配項
    • 允許像ShuffleConditionalSelect這樣的情況下的非確定性行為
    • 這些API在當今的所有平臺上都有定義良好的行為,例如Shuffle將任何超出範圍的索引視為將目標元素歸零
    • 新的API(如ShuffleUnsafe)將允許超出範圍索引的不同行為
    • 對於這種情況,Arm64將具有相同的行為,而x64只有在設置了最高有效位時才具有相同的行為
  • 其他模式識別,例如
    • 嵌入式屏蔽(AVX 512,AVX 10,SVE/SVE 2)
    • 組合位操作(AVX512上的vpternlog
    • 有限的JIT時間常數摺疊機會
      作者:zyl910 出處:http://www.cnblogs.com/zyl910/ 版權聲明:自由轉載-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0.
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1 文本Embedding 將整個文本轉化為實數向量的技術。 Embedding優點是可將離散的詞語或句子轉化為連續的向量,就可用數學方法來處理詞語或句子,捕捉到文本的語義信息,文本和文本的關係信息。 ◉ 優質的Embedding通常會讓語義相似的文本在空間中彼此接近 ◉ 優質的Embedding相 ...
  • 前言 最近自己做了個 Falsk 小項目,在部署上伺服器的時候,發現雖然不乏相關教程,但大多都是將自己項目代碼複製出來,不講核心邏輯,不太簡潔,於是將自己部署的經驗寫成內容分享出來。 uWSGI 簡介 uWSGI: 一種實現了多種協議(包括 uwsgi、http)並能提供伺服器搭建功能的 Pytho ...
  • 初識STL STL,(Standard Template Library),即"標準模板庫",由惠普實驗室開發,STL中提供了非常多對信息學奧賽很有用的東西。 vector vetor是STL中的一個容器,可以看作一個不定長的數組,其基本形式為: vector<數據類型> 名字; 如: vector ...
  • 拓展閱讀 資料庫設計工具-08-概覽 資料庫設計工具-08-powerdesigner 資料庫設計工具-09-mysql workbench 資料庫設計工具-10-dbdesign 資料庫設計工具-11-dbeaver 資料庫設計工具-12-pgmodeler 資料庫設計工具-13-erdplus ...
  • .NET 部署 IIS 的簡單步驟一: 下載 dotnet-hosting-x.y.z-win.exe ,下載地址:.NET Downloads (Linux, macOS, and Windows) (microsoft.com) .NET 部署 IIS 的簡單步驟二: 選擇對應的版本,點擊進入詳 ...
  • 在處理大型Excel工作簿時,有時候我們需要在工作表中凍結窗格,這樣可以在滾動查看數據的同時保持某些行或列固定不動。凍結窗格可以幫助我們更容易地導航和理解複雜的數據集。相反,當你不需要凍結窗格時,你可能需要解凍它們以獲得完整的視野。 下麵將介紹如何使用免費.NET庫通過C#實現凍結Excel視窗以鎖 ...
  • 在 Avalonia 中,樣式是定義控制項外觀的一種方式,而控制項主題則是一組樣式和資源,用於定義應用程式的整體外觀和感覺。本文將深入探討這些概念,並提供示例代碼以幫助您更好地理解它們。 樣式是什麼? 樣式是一組屬性,用於定義控制項的外觀。它們可以包括背景色、邊框、字體樣式等。在 Avalonia 中,樣 ...
  • 引言 上一篇我們創建了一個Sample.Api項目和Sample.Repository,並且帶大家熟悉了一下Moq的概念,這一章我們來實戰一下在xUnit項目使用依賴註入。 Xunit.DependencyInjection Xunit.DependencyInjection 是一個用於 xUnit ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...