关键词网站建设公司网站建设模板html

当前位置: 首页 > news >正文

关键词网站建设公司,网站建设模板html,全网营销网站建设特点,免费做网站收录的自从我们启动快速发展的 .NET 开源和跨平台项目以来#xff0c;.NET 发生了很大变化。我们重新思考并完善了该平台#xff0c;添加了专为性能和安全性而设计的新低级功能#xff0c;以及以生产力为中心的高级功能。SpanT、硬件内在函数和可为空的引用类型都是示例。…自从我们启动快速发展的 .NET 开源和跨平台项目以来.NET 发生了很大变化。我们重新思考并完善了该平台添加了专为性能和安全性而设计的新低级功能以及以生产力为中心的高级功能。SpanT、硬件内在函数和可为空的引用类型都是示例。我们正在启动一个新的“.NET 设计要点”系列文章以探索定义当今 .NET 平台的基础知识和设计选择以及它们如何使您现在编写的代码受益。 本系列的第一篇文章全面概述了平台的支柱和设计要点。当您选择 .NET 时它在基础级别上描述了“您得到了什么”旨在成为一个充分且以事实为中心的框架您可以使用它来向其他人描述该平台。后续帖子将更详细地介绍这些相同的主题因为这篇帖子并没有完全公正地介绍这些功能中的任何一个。这篇文章不描述工具如 Visual Studio也不涵盖更高级的库和应用程序模型如 ASP.NET Core 提供的那些。 我们所说的“.NET”是现代的 .NET Core。我们在 GitHub 上作为开源项目于2014年启动了这个项目。它在 Arm64、x64 和其他芯片架构上的 Linux、macOS 和 Windows 上运行。它在一堆 Linux 发行版中可用。它与 .NET Framework 保持了很大的兼容性但又是一个全新的方向和产品。 .NET 设计要点 .NET 平台代表生产力、性能、安全性和可靠性。.NET 在这些价值之间取得的平衡使其具有吸引力。 .NET 的设计要点可以归结为在安全域一切都高效和不安全域存在大量功能中都有效和高效。.NET 可能是具有最多内置功能的托管环境同时还提供最低的与外部世界互操作的成本并且两者之间没有权衡。事实上许多功能都利用了这种无缝划分在底层操作系统和 CPU 的原始能力和功能上构建安全的托管 API。 我们可以进一步扩展设计点 生产力是跨运行时、库、语言和工具的首要设计考虑因素。安全代码是主要的计算模型而不安全代码支持额外的手动优化。支持静态和动态代码支持广泛的不同场景。本机代码互操作和硬件内在函数成本低且保真度高原始 API 和指令访问。代码可跨平台操作系统、芯片架构移植而平台定位则支持专业化和优化。通过通用编程模型的专门实现可以实现跨编程域云、客户端、游戏的适应性。OpenTelemetry 和 gRPC 等行业标准优于定制解决方案。.NET 堆栈的支柱 运行时、库和语言是 .NET 堆栈的支柱。更高级别的组件如 .NET 工具和应用程序堆栈如 ASP.NET Core构建在这些支柱之上。这些支柱具有共生关系由一个团队Microsoft 员工和开源社区共同设计和构建致力于这些组件的多个方面并为其提供信息。 C# 是面向对象的运行时支持面向对象。C# 需要垃圾收集运行时提供跟踪垃圾收集器。事实上将 C#以其完整形式移植到没有垃圾收集的系统是不可能的。这些库以及应用程序堆栈将这些功能塑造成概念和对象模型使开发人员能够在直观的工作流程中高效地编写算法。 C# 是一种现代的、安全的、通用的编程语言涵盖了从面向数据的记录等高级功能到函数指针等低级功能。它提供静态类型以及类型和内存安全作为基准功能同时提高开发人员的工作效率和代码安全性。C# 编译器也是可扩展的支持插件模型使开发人员能够通过额外的诊断和编译时代码生成来增强系统。 许多 C# 功能已经影响或受最先进的编程语言的影响。例如C# 是第一个引入 async and await. 同时C# 借鉴了其他编程语言中首先引入的概念例如采用模式匹配和主构造函数等函数式方法。 核心库公开了数千种类型其中许多类型与 C# 语言集成并为其提供动力。例如C# 的 foreach 支持枚举任意集合基于模式的优化使 ListT 等集合能够被简单高效地处理。资源管理可能留给垃圾收集但可以通过 IDisposable 和 using 中的直接语言支持进行快速清理。 C# 中的字符串插值既富有表现力又高效与 string 、StringBuilder 和 SpanT 等跨核心库类型的实现集成并受其支持。语言集成查询 (LINQ)功能由库中的数百个序列处理例程提供支持例如 Where、Select 和 GroupBy具有支持内存中和远程数据源的可扩展设计和实现。从压缩到密码学再到正则表达式列表还在继续直接集成到语言中的内容只是作为核心 .NET 库的一部分公开的功能的表面。一个全面的从套接字到 HTTP/3 的网络堆栈是一个独立的领域。同样库支持处理无数格式和语言如 JSON、XML 和 tar。 .NET 运行时最初称为“公共语言运行时 (CLR)”。它继续支持多种语言一些由 Microsoft 维护例如 C#、F#、Visual Basic、C/CLI 和 PowerShell一些由其他组织维护例如 Cobol、Java、PHP、Python、Scheme。许多改进与语言无关这会引发所有改善。 接下来我们将看看它们一起提供的各种平台特性。我们可以分别详细说明这些组件中的每一个但您很快就会看到它们在交付 .NET 设计点方面进行合作。让我们从类型系统开始。 类型系统 .NET 类型系统提供了显著的广度大致同等地满足了安全性、描述性、动态性和本机互操作性。 首先类型系统支持面向对象的编程模型。它包括类型、单个基类继承、接口包括默认方法实现和虚拟方法分派为面向对象允许的所有类型分层提供合理的行为。 泛型是一种普遍的特性它允许将类专门化为一种或多种类型。例如ListT 是一个开放的通用类而像 Liststring 和 Listint 这样的实例化避免了对单独的 ListOfString 和 ListOfInt 类的需要或者像 ArrayList 那样依赖 object 和强制转换。泛型还可以跨不同类型创建有用的系统并减少对大量代码的需求例如 Generic Math。 Delegates 和 lambdas 允许将方法作为数据传递这使得将外部代码集成到另一个系统拥有的操作流中变得容易。它们是一种“胶水代码”它们的签名通常是通用的可以广泛使用。 app.MapGet(/Product/{id}, async (int id)
{ if (await IsProductIdValid(id)) { return await GetProductDetails(id); } return Products.InvalidProduct; });
这种对 lambdas 的使用是 ASP.NET Core Minimal APIs 的一部分。它可以直接向路由系统提供端点实现。在更新的版本中ASP.NET Core 更广泛地使用了类型系统。 与 .NET 的 GC 管理类型相比值类型和堆栈分配的内存块提供了对数据和本机平台互操作的更直接、低级别的控制。.NET 中的大多数原始类型如整数类型都是值类型用户可以定义自己具有相似语义的类型。 .NET 的泛型系统完全支持值类型这意味着像 ListT 这样的泛型类型可以提供值类型集合的平坦、无开销的内存表示。此外.NET 泛型在替换值类型时提供专门的编译代码这意味着这些泛型代码路径可以避免昂贵的 GC 开销。 byte magicSequence 0b1000_0001; Spanbyte data stackalloc byte[128]; DuplicateSequence(data[0..4], magicSequence);
此代码生成堆栈分配的值。Spanbyte 是 byte* 的安全和更丰富的版本提供长度值带边界检查和方便的跨度切片。 Ref 类型和变量是一种小型编程模型它提供对类型系统数据的较低级别和更轻量级抽象。这包括 SpanT。此编程模型不是通用的包括维护安全的重要限制。 internal readonly ref T _reference; 这种使用 ref 导致将指针复制到底层存储而不是复制该指针引用的数据。默认情况下值类型是“按值复制”。ref 提供“按引用复制”行为可以提供显著的性能优势。 自动内存管理 .NET 运行时通过垃圾收集器 (GC) 提供自动内存管理。对于任何语言其内存管理模型可能是其最具决定性的特征。.NET 语言也是如此。 工程师花费数周甚至数月的时间来追踪这些问题的情况并不少见。许多语言使用垃圾收集器作为消除这些错误的用户友好方式因为 GC 确保正确的对象生命周期。通常GC 会分批释放内存以高效运行。这会导致暂停如果您对延迟要求非常严格这可能不适合并且内存使用率会更高。GC 往往具有更好的内存局部性并且某些 GC 能够压缩堆使其不易产生内存碎片。 .NET 具有自我调整、跟踪 GC。它旨在一般情况下提供“放手”操作同时为更极端的工作负载提供配置选项。GC 是多年投资、改进和从多种工作负载中学习的结果。 ▌Bump 指针分配 通过指针递增所需的大小分配对象而不是在分离的空闲块中寻找空间因此一起分配的对象往往会在一起。由于用户经常一起访问不同对象这样做可以实现更好的内存局部性 memory locality 这有利于保证性能。 ▌分代收集 对象生命周期遵循分代假设 generational hypothesis 是非常常见的对象生存周期要么很长要么很短。因此对于 GC 来说如果大部分运行时只收集临时对象占用的内存称为临时 GC 而不是每次运行时都必须收集整个堆称为完整 GC 那么效率就要高得多。 ▌压缩 相同数量的可用空间在面积大而数量少的块中比在面积小和数量多的块中更有用。在压缩 GC 期间仍然存在的对象会被移动到一起由此可以形成更大的自由空间。这种行为需要比非移动 GC 更复杂的实现因为它需要更新对这些移动对象的引用。.NET GC 被动态调整为仅在确定回收的内存高于 GC 成本时才执行压缩。这意味着临时集合通常会被压缩。 ▌并行 GC 工作可以在单个线程或多个线程上运行。Workstation flavor 在单个线程上进行 GC而 Server flavor 在多个 GC 线程上进行这样可以更快结束作业。服务器 GC 还可以适应更大的分配率因为有多个堆供应用程序分配因此它对吞吐量适应性也很好。 ▌并发 在用户线程暂停时进行 GC 工作称为 Stop-The-World这样使实现需求更简单但这些暂停可能对于 GC 来说是不可接受的。.NET 提供 concurrent flavor 来缓解该问题。 ▌固定 .NET GC 支持对象固定它可以实现与本机代码的零拷贝互操作。此功能可实现高性能和高保真度的本机互操作同时限制 GC。 ▌独立 GC 可以使用具有不同机制的独立 GC通过配置指定并满足 interface requirements)。这样一来调查和尝试新功能就更容易了。 ▌诊断 GC 提供有关内存和集合的大量信息这允许您将数据与系统的其余部分相关联。例如您可以通过捕获 GC 事件并将它们与其他事件如 IO相关联来评估 GC impact of your tail latency 尾部延迟对 GC 的影响以计算 GC 对其他因素的影响程度这样您就可以将精力集中在正确的组件上。 安全 .NET 编程安全一直是过去十年的热门话题之一。它是 .NET 等托管环境的固有组件。 安全形式 Type safety 类型安全 — 不能使用任意类型代替另一个类型避免未定义的行为。Memory safety 内存安全 — 不能使用任意类型代替另一个类型避免未定义的行为。Concurrency or thread safety 并发或线程安全 — 不能使用任意类型代替另一个类型避免未定义的行为。 .NET 从最初的设计开始就被设计成一个保证安全的平台。特别需要指出的是它旨在启用新一代 Web 服务器这些服务器一直需要在世界上复杂的计算环境Internet中接受不受信任的输入的考验。现在普遍认为网络程序应该用安全的语言编写。 类型安全由语言和运行时模块同时强制执行。编译器验证静态不变量例如分配不同的类型——例如分配 string 给 Stream——这将导致编译器中产生错误。运行时验证动态不变量例如不同类型之间的转换就将产生 InvalidCastException。 内存安全主要由代码生成器如 JIT和垃圾收集器合作实现。变量引用值要么是活动对象要么是 null要么超出范围。默认情况下内存是自动初始化的这样新对象就不会使用未初始化的内存。边界检查禁止访问数组中无效索引的元素读取未定义的内存——通常由一个单位的错误偏移引起——这会导致 IndexOutOfRangeException。 Cnull 处理是保证内存安全的一种特殊形式。可空引用类型 Nullable reference types 是一种 C# 语言和编译器功能可静态标识未安全处理的代码 null。特别是如果您取消引用可能为 null 的变量编译器会发出警告。您还可以禁止 null 赋值这样编译器会在您可能给变量赋空值时发出警告。运行时具有匹配的动态验证功能可通过抛出 NullReferenceException 来防止引用被访问。 C# 功能依赖于库中可为空的属性 nullable attributes 。它还依赖于它们在库和应用程序堆栈我们已经完成中的详尽应用以便为您的代码提供来自静态分析工具的准确结果。 .NET 中没有内置的并发安全。相反开发人员需要遵循模式和约定来避免未定义的行为。.NET 生态系统中还有分析器和其他工具可以深入了解并发问题。核心库包括多种可以安全并发使用的类型和方法例如支持任意数量的并发读取器和写入器而不会冒数据结构损坏风险的 concurrent collections 并发集合。 运行时公开安全和 unsafe code 不安全的代码模型。安全代码的安全性得到保证这是默认设置而开发人员必须选择使用不安全代码。不安全代码通常用于与底层平台互操作、与硬件交互或对性能关键路径实施手动优化。 沙箱 sandbox 是一种特殊的安全形式它提供隔离并限制组件之间的访问。我们依赖标准的隔离技术如进程和 CGroups、虚拟机和 WebAssembly具有不同的特性。 错误处理 异常是 .NET 中的主要错误处理模型。异常的好处是错误信息不需要在方法签名中表示或由每个方法处理。 下面的代码演示了一个典型的模式 try {var lines await File.ReadAllLinesAsync(file);Console.WriteLine(\(The {file} has {lines.Length} lines.); } catch (Exception e) when (e is FileNotFoundException or DirectoryNotFoundException) {Console.WriteLine(\){file} doesnt exist.); } 正确的异常处理对于应用程序的可靠性至关重要。可以在用户代码中有意处理预期的异常否则应用程序就会崩溃。崩溃的应用程序比具有未定义行为的应用程序更可靠。当您想找出问题的根本原因时它也更容易诊断。 异常从错误点抛出并自动收集有关程序状态的附加诊断信息。这些信息可用于交互式调试、应用程序可观察性和事后调试。这些诊断方法中的每一种都依赖于访问大量的错误信息和应用程序状态来诊断问题。 异常是为罕见的情况而设计的。这在一定程度上是因为它们的性能成本相对较高。它们不打算用于控制流即使它们有时以这种方式使用。 异常有一部分依赖于取消。一旦观察到取消请求它们就可以有效地停止执行并展开正在进行的调用堆栈。 try { await source.CopyToAsync(destination, cancellationToken); } catch (OperationCanceledException) { Console.WriteLine(Operation was canceled); } .NET 设计模式包括替代形式的错误处理以应对异常的性能成本过高的情况。例如int.TryParse 返回成功时其参数包含已解析的有效整数DictionaryTKey, TValue.TryGetValue 提供了一个类似的模型返回一个有效 TValue 类型作为案例中的参数等。 错误处理和更普遍的诊断是通过低级运行时 API、higher-level libraries 和 tools 实现的。这些功能旨在支持更新的部署选项例如容器。例如dotnet-monitor 可以通过内置的面向诊断的 Web 服务器将运行时数据从应用导出到侦听器。 并发 支持同时做多件事是几乎所有工作负载的基础无论是在保持 UI 响应的同时进行后台处理的客户端应用程序、处理成千上万同时请求的服务、响应大量同时刺激的设备还是高驱动的机器并行处理计算密集型操作。操作系统通过线程为这种并发性提供支持这使得多个指令流能够独立处理操作系统管理这些线程在机器中任何可用处理器内核上的执行。操作系统还提供对执行 I/O 的支持提供的机制使 I/O 能够以可扩展的方式执行并且在任何特定时间都有许多“运行中”的 I/O 操作。 .NET 通过库和深度集成到 C# 中在多个抽象级别提供此类并发和并行化支持。线程 Thread 类位于层次结构的底部代表一个操作系统线程使开发人员能够创建新线程并随后加入它们。线程池 ThreadPool 位于线程之上允许开发人员考虑异步安排在线程池上运行的工作项并这些线程的管理包括从池中添加和删除线程以及为这些线程分配工作项放在运行时。Task 然后为任何异步执行的操作提供统一的表示形式并且可以通过多种方式创建和连接例如Task.Run 允许在 ThreadPool 上运行安排委托并返回 Task 以表示该工作的最终完成同时 Socket.ReceiveAsync 返回一个Taskint或 ValueTaskint表示异步 I/O 的最终完成提供了大量的同步原语用于协调线程和异步操作之间的同步和异步活动并提供了大量高级 API 以简化常见并发模式的实现例如SocketParallel.ForEach 和 Parallel.ForEachAsync 使处理一个线程的所有元素变得更容易实现数据序列并行。 异步编程支持也是 C# 编程语言的一流功能它提供了 async 和 await 关键字使编写和组合异步操作变得容易同时仍然享受该语言必须提供的所有控制流结构的全部好处。 反射 反射是一种“程序即数据”范例它能让程序的一部分根据程序集、类型和成员动态查询和/或调用另一部分。它对于后期绑定编程模型和工具特别有用。 以下代码使用反射来查找和调用 type。 foreach (Type type in typeof(Program).Assembly.DefinedTypes) { if (type.IsAssignableTo(typeof(IStory)) !type.IsInterface) { IStory? story (IStory?)Activator.CreateInstance(type); if (story is not null) { var text story.TellMeAStory(); Console.WriteLine(text); } } } interface IStory { string TellMeAStory(); } class BedTimeStore : IStory { public string TellMeAStory() Once upon a time, there was an orphan learning magic …; } class HorrorStory : IStory { public string TellMeAStory() On a dark and stormy night, I heard a strange voice in the cellar …; }
此代码动态枚举实现特定接口的所有程序集类型实例化每个类型的实例并通过该接口调用对象的方法。代码本来可以静态编写的因为它只查询它所引用的程序集中的类型但要这样做需要将所有实例的集合也许是作为一个 ListIStory交给它来处理。如果此算法从加载项目录加载任意程序集则更有可能使用这种后期绑定方法。有这样一种情况您无法提前获取程序集和类型反射通常就被用在这样的场景中。 反射可能是 .NET 中提供的最动态的系统。它旨在使开发人员能够创建自己的二进制代码加载器和方法分派器其语义可以与静态代码策略由运行时定义相匹配或有所区别。反射公开了一个丰富的对象模型它可以直接用于简单的用例但随着场景变得更加复杂您就需要更深入地了解 .NET 类型系统。 反射还启用了一种单独的模式其中生成的 IL 字节代码可以在运行时进行 JIT 编译有时用于以专用算法替换通用算法。有了对象模型和其他细节它通常会被用于序列化器或对象关系映射器中。  编译后的二进制格式 应用程序和库被编译为 PE/COFF 格式的标准化跨平台字节码。二进制分发最重要的是性能特征。它使应用程序能够扩展到越来越多的项目。每个库都包含一个导入和导出类型的数据库称为元数据它对开发操作和运行应用程序都起着重要作用。 编译的二进制文件包括两个主要方面 二进制字节码——简洁而规则的格式无需在高级语言编译器如 C#编译后解析文本源。元数据——描述导入和导出的类型包括给定方法的字节代码的位置。 例如对于开发工具可以有效地读取元数据以确定给定库公开的类型集以及哪些类型实现了某些接口。此过程可加快编译速度并使 IDE 和其他工具能够准确呈现给定上下文的类型和成员列表。 对于运行时元数据使库能够延迟加载方法体更是如此。上文讨论过的反射是元数据和 IL 的运行时 API。还有其他更适合工具的 API。 随着时间的推移IL 格式一直保持向后兼容。最新的 .NET 版本仍然可以加载和执行由 .NET Framework 1.0 编译器生成的二进制文件。 共享库通常通过 NuGet 包分发。默认情况下带有单个二进制文件的 NuGet 包可以在任何操作系统和体系结构上运行但也可以专门用于在特定环境中提供特定行为。  代码生成 .NET 字节码不是机器可执行的格式它需要通过某种形式的代码生成器使其可执行。这可以通过提前 (AOT) 编译、即时 (JIT) 编译、解释或转译来实现。事实上这些都是今天在各种场景中使用的。 .NET 以 JIT 编译而闻名。JIT 在应用程序运行时将方法和其他成员编译为本机代码并且仅在需要时才将其编译因此得名“及时just in time缩写为 JIT”。例如一个程序在运行时可能只调用一种类型中几种方法中的一种。JIT 还可以利用仅在运行时可用的信息如初始化的只读静态变量的值或程序运行的确切 CPU 模型并且可以多次编译相同的方法以便每次针对不同的目标进行优化并从以前的编译中吸取教训。 JIT 为给定的操作系统和芯片架构生成代码。.NET 具有支持 Arm64 和 x64 指令集以及 Linux、macOS 和 Windows 操作系统等的 JIT 实现。作为 .NET 开发人员您不必担心 CPU 指令集和操作系统调用约定之间的差异。JIT 负责生成 CPU 需要的代码。它还知道如何为每个 CPU 生成快速代码操作系统和 CPU 供应商经常帮助我们做到这一点。 AOT 类似只是代码是在程序运行之前生成的。开发人员选择 AOT 是因为它可以通过消除 JIT 完成的工作来显著缩短启动时间。AOT 构建的应用程序本质上是特定于操作系统和体系结构的这意味着需要额外的步骤才能使应用程序在多个环境中运行。例如如果您想支持 Linux 和 Windows 以及 Arm64 和 x64那么您需要构建四个变体以支持所有组合。AOT 代码也可以提供有价值的优化但总体不如 JIT 多。 代码生成器优化之一是内在函数。硬件内在函数就是 .NET API 直接转换为 CPU 指令的例子。这已在整个 .NET 库中普遍用于 SIMD 指令。  互操作 .NET 被特意设计用于与本机库的低成本互操作。.NET 程序和库可以无缝调用低级操作系统 API 或利用 C/C 库的庞大生态系统。现代 .NET 运行时专注于提供低级互操作构建块例如通过函数指针调用本机方法的能力将托管方法公开为非托管回调或自定义接口转换。.NET 也在这个领域不断发展在 .NET 7 中发布了源代码生成的解决方案进一步减少了开销并且便于使用 AOT。 下面的代码演示了 C# 函数指针的效率。 // Using a function pointer avoids a delegate allocation. // Equivalent to void (fptr)(int) Callback; in C delegate unmanagedint, void fptr Callback; RegisterCallback(fptr); [UnmanagedCallersOnly] static void Callback(int a) Console.WriteLine($Callback: {a}); [LibraryImport(…, EntryPoint RegisterCallback)] static partial void RegisterCallback(delegate* unmanagedint, void fptr);
此示例使用 .NET 7 中引入的 LibraryImport 源代码生成器。它位于现有 DllImport 或 P/Invoke 功能之上。 独立包通过利用这些低级构建块例如 ClangSharp、Xamarin.iOS 和 Xamarin.Mac、CsWinRT、CsWin32 和 DNNE 提供更高级别的特定于域的互操作解决方案。 这些新功能并不意味着内置运行时托管/非托管编组或 Windows COM 互操作等内置互操作解决方案没有用——我们知道它们有用而且人们已经开始依赖它们。那些之前内置到运行时中的功能将继续按原样提供支持只是为了向后兼容我们没有进一步发展它们的计划。所有未来的投资都将集中在互操作构建块以及它们支持的特定领域和更高性能的解决方案上。 二进制分布 Microsoft 的 .NET 团队维护着多个二进制发行版最近开始支持 Android、iOS 和 WebAssembly。该团队使用多种技术为这些环境中的每一个环境定制代码库。大多数平台是用 C# 编写的这使得移植可以集中在相对较小的组件集上。 社区维护着另一套发行版主要集中于 Linux 。例如.NET 已包含在 Alpine Linux、Fedora、Red Hat Enterprise Linux 和 Ubuntu中。  概括 我们有几个版本进入现代 .NET 时代最近发布了 .NET 7。我们认为如果我们总结自 .NET Core 1.0 以来我们一直在平台的最低级别构建的内容将会很有用。我们明确保留了原始 .NET 的精神结果是一个新平台开辟了一条新道路并为开发人员提供了新的和更多的价值。 让我们用最开始的话题结束本篇文章。.NET 代表四个值生产力、性能、安全性和可靠性。我们坚信当不同的语言平台提供不同的方法时开发人员会得到最好的服务。作为一个团队我们寻求为 .NET 开发人员提供高生产力同时提供在性能、安全性和可靠性方面处于领先地位的平台。 这篇文章由 Jan Kotas、Rich Lander、Maoni Stephens 和 Stephen Toub 撰写囊括了 .NET 团队同事的深刻见解和审阅。