ASP.NET Core 改进了.NET Framework 中的字符串处理

  • Jonathan Allen
  • Rays

2017 年 5 月 15 日

话题:.NET语言 & 开发架构

显然 Microsoft 开发人员和管理人员并没有表达清楚,事实上 ASP.NET Core 2.0 将会得到整个.NET Framework 的支持。当前的更改只实现了在 ASP.NET 上提供.NET Core,这是为了便于开发而采取的一个临时步骤。对此,在ASP.NET Core 预览发行声明中给出了如下的解释:

在发布 ASP.NET Core 2.0 预览版时,仅提供了对.NET Core 2.0 SDK 的支持。我们的目标是在.NET Standard 2.0 中发布 ASP.NET Core 2.0,使应用可运行在.NET Core、Mono 和.NET Framework 上。团队正致力于在 Build 大会之前解决最后一些问题,最突出的问题是在 ASP.NET Core 2.0 预览版中使用了.NET Standard 2.0 之外的 API,这妨碍了在.NET Framework 上的运行。由于这些问题,我们限制了 Preview 1 版本对.NET Core 的支持,以免对开发人员在.NET Framework 上将 ASP.NET Core 1.x 应用升级到 ASP.NET Core 2 预览版时造成破坏。

在 Register 的一次采访中,Miguel de Icaza 确认了 Microsoft 对.NET Framework 的承诺

我要对此做出澄清。我感到十分遗憾的是,即将推出的.NET Core 2.0 是我们专为 Build 大会准备,它只是一个预览版,因为我们发现其中存在一系列在.NET Framework 上无法很快得到解决的问题。因此,我们推出的软件包仅支持在.NET Core 2.0 上运行 ASP.NET Core 2.0。我们将会修复这个问题,.NET Core 2.0 终将运行在.NET Framework 上。

即便是临时性更改,一个依然需要解决的问题是:要想进一步改进 ASP.NET 的性能,需要提供更好的字符串处理库。

内存分配上的考虑

在.NET 中,几乎所有的字符串处理方法都要做内存分配,该问题长期以来一直为人所诟病。在解析 JSON、XML 等格式时,substring方法常会产生成百上千的微小字符串分配。这不仅耗费了大量时间生成拷贝,而且对垃圾回收造成了很大的压力。这并非应用开发人员所能掌控的。

这种做法有其合理性。与.NET 一样,在 Java 中字符串也是不可变的。而 Java 自带的substring方法并不分配新的字符串,它创建一个指向原始字符串的指针。虽然 Java 的substring方法无需分配内存,但是存在着内存泄漏的风险。一个字符串substring方法可以保留 5MB 字符串不被垃圾回收(这个问题相当恶劣,因此在 Java 1.7u6 版中做了更改,substring方法做内存分配)。

在“Span<T> 建议”中,开发人员可以选择使用两种不同的substring方法,即分配内存的方法和不做内存分配的方法。ASP.NET Core 所使用的解析库也可以被覆写,在内部使用不分配内存的substring方法。但在解析操作的最后阶段,需要确保释放所有 Span<char> 的实例。

这一更改还需要重新实现更高效的基本类型解析方法,例如 Int32.Parse 和 Inta32.TryParse 等。理想情况下,这些方法将会加入到基类库(BCL,Base Class Library)中,而不是以单独库的方式提供。这就回到了.NET Framework、Standard 和 Core 的对比问题上。

毫无疑问,可以加快对.NET Core 的更改过程。除了操作系统特定的功能,新特性将做优先更改。否则,只有得到所有.NET/Mono 的各种实体(incarnation)支持的新特性,才会出现在.NET Standard 中。虽然从理论上讲,这些实体也归属于 Microsoft 的,但是新特性的添加依然会是一个冗长的过程。

因此,在开发 ASP.NET Core 的过程中,基于 ASP.NET 进行构建是合乎情理的。这使得新的 API 在提交标准化前,得到真实用例的精炼。

默认编码上的考虑

并非所有开发人员都了解,在.NET 内部使用的是 UTF16 字符串。除了实现文件或网络 I/O 处理之外,对于大部分用例,开发人员都无需考虑编码问题。

Web 应用主要基于 UTF8 编码。同样,在处理大部分用例时,服务器端开发人员也无需考虑编码问题。只需确保无论使用何种内部格式,最终都会转换为 UTF8 编码。

当需考虑性能时,这种做法就存在问题。所有的 Web 请求最初都是以 UTF8 编码的,需要在被.NET 理解前转化为 UTF16 编码。反之,所有来自.NET 服务器的响应,需要由 UTF16 编码转化为 UTF8 编码。

现在已有一些建议方法,意在消除这种转换的必要。一种做法创建了Utf8String 类并匹配字符串处理库,之后就可以新建直接操作类的解析库。这一做法是完全“明确征得同意”(Opt In)的,因此风险很低。

更全面的建议是由 Matt Warren 提出的,称为“紧凑字符串(Compact String)实现”。该建议受到了OpenJDK 中类似建议的启发,它会在字符串中添加一个类型字段,用于指示所使用的编码。这是一种更大程度上的更改,对 Span<T> 存在一些负面影响。

查看英文原文:What ASP.NET Core May Bring to the .NET Framework’s String Handling

.NET语言 & 开发架构