Span<T>之高性能字符串操作实测

简介:

   .net中的字符串操作性能问题由来已久,幸运的是微软推出了span<T>高性能指针操作封装工具类。这个类到底有多高的性能呢?网上传言反正很高,但是实际上在网上很难找到合适的测试实例,这让本人实在无力吐槽。经不住高性能这三个字的诱惑,本人还是了解了一番后做了几个简单样例来测试一番,下面列出几种字符串常见操作的测试代码及其运行结果。

一、String.Index 测试

复制代码
1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.IndexOf(subStr);
6                 }
7             });
8 
9             Console.WriteLine($"string.IndexOf {count} 次用时:{t1} 毫秒");
复制代码
复制代码
 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 for (int i = 0; i < count; i++)
 8                 {
 9                     strSpan.IndexOf(subStrSpan);
10                 }
11             });
12 
13             Console.WriteLine($"Span<T>.IndexOf {count} 次用时:{t2} 毫秒");
复制代码

 

二、String.Substring 测试

复制代码
1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.Substring(0, str.IndexOf(subStr));
6                 }
7             });
8 
9             Console.WriteLine($"String.Substring {count} 次用时:{t1} 毫秒");
复制代码
复制代码
 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 var index = strSpan.IndexOf(subStrSpan);
 8 
 9                 for (int i = 0; i < count; i++)
10                 {
11                     strSpan.Slice(0, strSpan.IndexOf(subStrSpan));
12                 }
13             });
复制代码

三、String.Split 测试

复制代码
1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     var arr = str.Split(new string[] { splitStr }, StringSplitOptions.None);
6                 }
7             });
8 
9             Console.WriteLine($"String.Split {count} 次用时:{t1} 毫秒");
复制代码
复制代码
 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var splitSapn = splitStr.AsSpan();
 6 
 7                 int m = 0, n = 0;
 8 
 9                 for (int i = 0; i < count; i++)
10                 {
11                     List<string> arr = new List<string>();
12 
13                     while (true)
14                     {
15                         m = n;
16                         n = strSpan.IndexOf(splitSapn);
17                         if (n > -1)
18                         {
19                             arr.Add(strSpan.Slice(0, n).ToString());
20                             strSpan = strSpan.Slice(n + splitSapn.Length);
21                         }
22                         else
23                         {
24                             break;
25                         }
26                     }
27 
28                 }
29             });
30 
31             Console.WriteLine($"Span<T>.Split {count} 次用时:{t2} 毫秒");
复制代码

四、String.Replace 测试

复制代码
1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.Replace(splitStr, replaceStr);
6                 }
7             });
8 
9             Console.WriteLine($"String.Replace {count} 次用时:{t1} 毫秒");
复制代码
复制代码
 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var splitSapn = splitStr.AsSpan();
 6 
 7                 int m = 0, n = 0;
 8 
 9                 for (int i = 0; i < count; i++)
10                 {
11                     List<string> arr = new List<string>();
12 
13                     while (true)
14                     {
15                         m = n;
16                         n = strSpan.IndexOf(splitSapn);
17                         if (n > -1)
18                         {
19                             arr.Add(strSpan.Slice(0, n).ToString());
20                             strSpan = strSpan.Slice(n + splitSapn.Length);
21                         }
22                         else
23                         {
24                             break;
25                         }
26                     }
27                     string.Join(replaceStr, arr);
28                 }
29             });
30 
31             Console.WriteLine($"Span<T>.Replace {count} 次用时:{t2} 毫秒");
复制代码

 

  怎么样,经过上面的测试,是不是觉的Span<T>确实是名不虚传?的确,在上面几个常见场景中,Span<T>的高性能确实不同凡响,差不多是10倍的性能优势!看到这里,小伙伴们是不是觉的字符串操作全改成Span<T>就行了?那下面的两个测试会让大家看清现实,在String.Contains中表现还不如原生的。

一、String.Contains 测试

复制代码
1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     str.Contains(subStr);
6                 }
7             });
8 
9             Console.WriteLine($"string.Contains {count} 次用时:{t1} 毫秒");
复制代码
复制代码
 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 for (int i = 0; i < count; i++)
 8                 {
 9                     strSpan.Contains(subStrSpan, StringComparison.CurrentCulture);
10                 }
11             });
12 
13             Console.WriteLine($"Span<T>.Contains {count} 次用时:{t2} 毫秒");
复制代码

  仔细一看,不对啊,Span<T>的Contains里面有其它的大小写和语言相关的判断啊。好,那再换一个原生方法对比测试一下。

二、String.Compare 测试

复制代码
1             var t1 = StopWacherHelper.DoTimer(() =>
2             {
3                 for (int i = 0; i < count; i++)
4                 {
5                     string.Compare(str, subStr, true);
6                 }
7             });
8 
9             Console.WriteLine($"string.Compare {count} 次用时:{t1} 毫秒");
复制代码
复制代码
 1             var t2 = StopWacherHelper.DoTimer(() =>
 2             {
 3                 var strSpan = str.AsSpan();
 4 
 5                 var subStrSpan = subStr.AsSpan();
 6 
 7                 for (int i = 0; i < count; i++)
 8                 {
 9                     strSpan.Contains(subStrSpan, StringComparison.CurrentCultureIgnoreCase);
10                 }
11             });
12 
13             Console.WriteLine($"Span<T>.Contains {count} 次用时:{t2} 毫秒");
复制代码

  还是被反杀了,这说明Span<T>的这个Contains方法可能真的只能在某些地方才能用,不然性能反而会有所下降。

 

目录
相关文章
|
算法 Java 测试技术
Java实现数据压缩所有方式性能测试
Java实现数据压缩所有方式性能测试
424 0
|
6月前
|
算法 Linux 测试技术
Linux编程:测试-高效内存复制与随机数生成的性能
该文探讨了软件工程中的性能优化,重点关注内存复制和随机数生成。文章通过测试指出,`g_memmove`在内存复制中表现出显著优势,比简单for循环快约32倍。在随机数生成方面,`GRand`库在1000万次循环中的效率超过传统`rand()`。文中提供了测试代码和Makefile,建议在性能关键场景中使用`memcpy`、`g_memmove`以及高效的随机数生成库。
|
7月前
|
缓存 自然语言处理 JavaScript
万字长文深度解析JDK序列化原理及Fury高度兼容的极致性能实现
Fury是一个基于JIT动态编译的高性能多语言原生序列化框架,支持Java/Python/Golang/C++/JavaScript等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
168719 12
|
7月前
|
存储 并行计算 算法
没错,列式存储非常牛。但是,Ta还可以更高效
没错,列式存储非常牛。但是,Ta还可以更高效
|
机器学习/深度学习 存储 NoSQL
X-SIMD高性能跨平台向量化加速库
X-SIMD是平头哥基于开源SIMDe开发的一个header-only C程序库,提供了一种简单易用的跨平台SIMD程序优化方案,旨在为不支持SIMD指令集的平台提供SIMD支持。X-SIMD可以帮助开发者快速完成应用软件迁移arm平台,减少用户重新编写SIMD算法工作量。
|
算法 搜索推荐 Java
高性能排序函数实现方案
如C语言的qsort()、Java的Collections.sort(),这些排序函数如何实现?
72 0
|
存储 测试技术 块存储
Python 大数据量文本文件高效解析方案代码实现
Python 大数据量文本文件高效解析方案代码实现
245 0
|
Arthas 缓存 算法
如何写出高性能代码(二)巧用数据特性
同一份逻辑,不同人的实现的代码性能会出现数量级的差异; 同一份代码,你可能微调几个字符或者某行代码的顺序,就会有数倍的性能提升;同一份代码,也可能在不同处理器上运行也会有几倍的性能差异;十倍程序员 不是只存在于传说中,可能在我们的周围也比比皆是。十倍体现在程序员的方法面面,而代码性能却是其中最直观的一面。
187 0
如何写出高性能代码(二)巧用数据特性
|
存储 Java
一种高性能单模正则表达式引擎
背景正则表达式匹配引擎的实现方式分为NFA(非确定有穷自动机,Non-deterministic finite automaton)和DFA(确定有穷自动机,Deterministic finite automaton)两类。由于NFA的状态数量与正则串长度成正比,因此大量开源库采用了NFA的执行方式,比如JDK regex、joni。也有一部分正则库在NFA翻译为DFA的理论基础上,采用了处理速
一种高性能单模正则表达式引擎