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

.NET/C# 使用 SpanT 为字符串处理提升性能

.NET Core 2.1 和 C# 7.2 带来了 Span 的原生支持,原本需要使用不安全代码操作的内存块现在可以使用安全的方式来完成。此前在性能和稳定性上需要有所取舍,而现在可以兼得了。


简单的例子

先来看一个字符串处理时使用 Span<T> 的最简单的例子:

using System;
using System.Text;

namespace Walterlv.Demo.StringSpan
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var text = "https://walterlv.github.io/";
            var nameSpan = text.AsSpan(8, 8);

            var builder = new StringBuilder("Hello ");
            builder.Append(nameSpan);
            builder.AppendLine("!");

            Console.WriteLine(builder.ToString());
        }
    }
}

这个例子是从 https://walterlv.github.io/ 字符串中取出第 8 个字符开始长度为 8 的部分,随后与其它字符串进行拼接。最后,我们得到了拼接的字符串:

Hello walterlv!

这种方式取出字符串替代了 SubString 这种会额外生成临时字符串的方式。如果上述代码发生在较大或较多文本的处理中,那么反复的拼接将生成大量的临时字符串,造成大量 GC 压力;而使用 Span<T> 将不会额外生成任何临时字符串。

语言/框架的支持

然而,只有 .NET Core 2.1 是原生支持字符串的 AsSpan<T> 方法的,.NET Core 2.0、.NET Framework 4.7.2 是不支持的。.NET Core 2.0 可以无视,因为有了 2.1。但 .NET Framework 的低版本却不能无视,因为用户的计算机上通常都是安装低版本的 .NET Framework。

只有 .NET Core 2.1 支持

然而我们可以安装 System.Memory,以在低版本的 .NET 中获得字符串扩展方法 AsSpan<T> 的支持。

那么问题来了,低版本的 .NET StringBuilder 中并没有提供 Append(ReadOnlySpan<char>) 方法,于是我们即便使用高性能的方式得到了字符串的一个片段,依然无法将其反复进行拼接。

这真是一个悲伤的故事

低版本 .NET 中有限的字符串性能提升

缺少了 StringBuilderReadOnlySpan<char> 的支持,广泛使用的字符串拼接功能便没有办法获得 Span 的支持。

不过,System.Memory 中提供了其它有限的字符串处理支持,来源于以下两个类型:

  • System.Buffers.Text.Utf8Parser
  • System.Buffers.Text.Utf8Formatter

前者提供从 ReadOnlySpan<char>Int32DoubleDateTimeGuid 等类型的解析,后者提供相反的转换。

期待 Microsoft 在未来版本的 System.Memory 库中提供对字符串拼接在低版本 .NET 生态中的支持。


参考资料

  • Welcome to C# 7.2 and Span - .NET Blog
  • C# 7.2: Understanding Span - Connect(); 2017 - Channel 9
  • C# Span 入门

相关文章:

  • WPF 应用完全模拟 UWP 的标题栏按钮
  • 让控制台支持 ANSI 转义序列,输出下划线、修改颜色或其他控制
  • 在 GitHub 公开仓库中隐藏自己的私人邮箱地址
  • Win32 程序在启动时激活前一个启动程序的窗口
  • C#/.NET 读取或修改文件的创建时间和修改时间
  • 通过解读 WPF 触摸源码,分析 WPF 插拔设备触摸失效的问题(问题篇)
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)
  • .NET 中 GetProcess 相关方法的性能
  • 常用输入法快速输入自定义格式的时间和日期(搜狗/QQ/手心/微软拼音)
  • 好的框架需要好的 API 设计 —— API 设计的六个原则
  • .NET/C# 使用反射注册事件
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • WPF 多线程 UI:设计一个异步加载 UI 的容器
  • .NET 命令行参数包含应用程序路径吗?
  • JavaScript-如何实现克隆(clone)函数
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • CSS盒模型深入
  • Docker入门(二) - Dockerfile
  • Flannel解读
  • HTML-表单
  • javascript 哈希表
  • js中的正则表达式入门
  • Laravel Mix运行时关于es2015报错解决方案
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 前端面试之闭包
  • 一些css基础学习笔记
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • 阿里云移动端播放器高级功能介绍
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • 树莓派用上kodexplorer也能玩成私有网盘
  • #100天计划# 2013年9月29日
  • #FPGA(基础知识)
  • #在 README.md 中生成项目目录结构
  • (1)(1.8) MSP(MultiWii 串行协议)(4.1 版)
  • (arch)linux 转换文件编码格式
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (论文阅读11/100)Fast R-CNN
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (一)u-boot-nand.bin的下载
  • (转)iOS字体
  • (转)我也是一只IT小小鸟
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .net 后台导出excel ,word
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET框架设计—常被忽视的C#设计技巧
  • @javax.ws.rs Webservice注解
  • [ IOS ] iOS-控制器View的创建和生命周期
  • [<事务专题>]
  • [BIZ] - 1.金融交易系统特点
  • [C#]winform利用seetaface6实现C#人脸检测活体检测口罩检测年龄预测性别判断眼睛状态检测
  • [C++]指针与结构体
  • [Codeforces1137D]Cooperative Game