[译] .NET 8 中的硬件内在函数(支持 Wasm 和 AVX-512)

这篇具有很好参考价值的文章主要介绍了[译] .NET 8 中的硬件内在函数(支持 Wasm 和 AVX-512)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

原文链接:
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的地方

我们加速了以下案例:

  • System.Collections.BitArray – creation, bitwise and, bitwise or, bitwise xor, bitwise not
  • System.Linq.Enumerable – Max and Min
  • System.Buffers.Text.Base64 – Decoding, Encoding
  • System.String – Equals, IgnoreCase
  • System.Span – IndexOf, IndexOfAny, IndexOfAnyInRange, SequenceEqual, Reverse, Contains, etc

在.NET库和一般的.NET生态系统中还有其他例子,太多了,无法列出和覆盖。这些包括但不限于颜色转换、图像处理、机器学习、文本转码、JSON解析、软件渲染、光线跟踪、游戏加速等场景。

接下来呢?

我们计划继续改进.NET中的硬件内部支持,无论何时何地。请注意,以下项目是前瞻性的思考和推测。该列表是不完整的,我们不提供任何这些功能将土地或当他们将船舶,如果他们这样做。

我们长期路线图中的一些项目包括以下内容:文章来源地址https://www.toymoban.com/news/detail-850440.html

  • 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时间常数折叠机会
 
 
 

到了这里,关于[译] .NET 8 中的硬件内在函数(支持 Wasm 和 AVX-512)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 支持硬件加速的opencv编译

    为了降低cpu的使用率提升系统的接入能力,需要将编解码模块移至GPU处理,opencv默认的发行版中不支持GPU加速,所以需要重新编译opencv使其支持GPU硬件加速。 本文的读者须具备一定的Linux使用经验,如常规软件安装等操作不在本文档中描述。 cuda:统一计算设备架构(Compute

    2024年02月10日
    浏览(42)
  • STM32F407单片机通用24CXXX读写程序(KEIL),兼容24C系列存储器(24C01到24C512),支持存储器任意地址跨页连续读写多个页

    原文链接:https://blog.csdn.net/ba_wang_mao/article/details/108318633 AT24C01,AT24C02,AT24C04,AT24C08,AT24C16,AT24C32,AT24C64,AT24C128,AT24C256…不同的xxx代表不同的容量。 总容量(Byte容量) = 页数 × 页内字节单元数。 对AT24CXXX进行读写操作时,都得先访问存储地址、比如AT24C01写一个字节的I

    2024年04月11日
    浏览(62)
  • 解决MATLAB硬件支持包无法下载的问题

    官方链接: https://ww2.mathworks.cn/support/install/support-software-downloader.html CSDN免费链接: https://download.csdn.net/download/m_life/87707725?spm=1001.2014.3001.5503 百度网盘:链接: 任意路径下双击安装程序 安装后自动弹出界面 登录matlab账号,选择自己的matlab的版本 选择所需的支持包 下载,window

    2024年02月06日
    浏览(28)
  • FPGA硬件png图片解码器,支持所有颜色类型解码,提供工程源码和技术支持

    png 是仅次于jpg的第二常见的图象压缩格式。png支持透明通道(A通道),支持无损压缩,支持索引RGB(基于调色板的有损压缩)。在色彩丰富的数码照片中,png只能获得1~4倍的压缩比。在人工合成图(例如平面设计)中,png能获得10倍以上的压缩比。 本设计使用system verilog语言

    2023年04月17日
    浏览(51)
  • Ubuntu 18.04 安装ffmpeg(支持GPU硬件加速)

    1:安装前请自行安装nvidia驱动和cudu cudnn 查看cuda版本 2:安装nv-codec-hearers 官网: https://docs.nvidia.com/video-technologies/video-codec-sdk/ffmpeg-with-nvidia-gpu/ 3:安装ffmpeg编码库 4:安装ffmpeg 5:建立软连接 增加安装目录的动态链接库 6 检查硬件加速 7:添加库连接 8 :运行实例检查 9:卸载

    2023年04月18日
    浏览(109)
  • 内存条@种类@型号@插槽@电脑支持的最大内存@升级内存硬件

    确认电脑最大支持内存大小和频率规格上限通常可以通过以下几种方式: 查阅主板或电脑型号规格 : 确定您的电脑或主板的具体型号。 访问主板制造商的官方网站,查找对应型号的产品页面或用户手册,那里会有详细的硬件规格说明,包括最大支持内存容量和内存频率。

    2024年04月26日
    浏览(87)
  • FX PLC手机版程序设计仿真软件(支持软件及硬件下载在线仿真)

    简介: PLC程序设计是一款安卓/鸿蒙手机PLC梯形图编程仿真器,软件支持三菱FX PLC编程指令,支持软件及硬件(通过蓝牙现国产高FX PLC工控板及部份三菱FX PLC)程序下载及在线调试仿真,软件自带3D动画实例仿真,适合电工及自动化爱好者学习PLC编程技术。也适合电气工程人员开

    2024年04月10日
    浏览(48)
  • FFmpeg 在Windows环境下 Intel ,Nvidia ,AMD 硬件加速编解码支持列表

    目录 前言 一. Intel 编解码硬件支持列表   1. Encode 编码硬件支持列表 (1)Intel 独显编码硬件支持列表 (2)第 11,12,13 代 Intel 处理器编码硬件支持列表 (3)第 10 代 Intel 处理器编码硬件支持列表 (4)第 9 代 Intel 处理器编码硬件支持列表 (5)第 5,6,7,8 代 Intel 处理器

    2024年02月03日
    浏览(48)
  • .Net6 .Net7 支持的 Windows 版本

    .NET 6 支持下列 Windows 版本: (OS) Version 体系结构 Windows 11 21H2 x64、Arm64 Windows 10 客户端 1607+ x64、x86、Arm64 Windows 客户端 7 SP1+、8.1 x64、x86 Windows Server 2012+ x64、x86 Windows Server 核心 2012+ x64、x86 Nano Server 1809+ X64 如果要在以下 Windows 版本上安装 .NET SDK 或运行时,则需要其他依赖项:

    2024年02月16日
    浏览(34)
  • Eazfuscator.NET 2021.4 学习版 支持.Net6混淆

    Eazfuscator.NET是.NET 平台的工业级混淆器 。Eazfuscator.NET就像 1-2-3 一样简单。它可以保护您的代码,而不会破坏它 —— 即使在最复杂的情况下 —— 我们已经处理好了。您可以将Eazfuscator.NET视为一个很好的合作伙伴,他可以为您提供很多帮助,并且仍然不会因为他的任何问

    2024年02月12日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包