C#里面滥用String造成的性能问题
前两天给我们的json
写一个解析函数, 之前用的正宗的json parser
, 支持完整的json
特性. 但是实际上我们用到特性, 只有key-value
的映射, value的类型只有数字
和字符串
两种类型. 由于parse的速度比较慢, 所以我打算自己用字符串解析一遍. 第一个能工作的原型出来的时候, 速度和json解析差不多. 做了profile之后发现, 绝大部分时间都浪费在构造String
和检索IndexOf
上面.
下了coreclr的源码研究了一下, 发现String.Split
在实现的时候, 先扫描一遍split
, 计算有多少个元素, 然后分配一个Array
, 然后再去做Split
操作. Split操作里面还会再new一个新的String出来, 顺便做一下拷贝. 看到这里我就惊呆了, 本来String在C#和Jawa这两个托管语言里面都是不可变的, 那么为什么他们不用一个Slice
去构造一个SubString
呢?
网上搜了一下, 也没发现有人写的StringSlice
或者类似的东西, 我就顺手撸了一个StringView
, 一个只读的StringSlice
.
using System.Collections.Generic; public unsafe struct StringView
{
public static readonly StringView Empty = new StringView(""); public StringView(string str) : this(str, , str.Length) { } public StringView(string str, int begin, int length)
{
this.str = str;
this.begin = begin;
this.length = length;
if (str.Length <= ) return; if (this.begin < ||
this.begin >= this.str.Length ||
this.begin + this.length > this.str.Length)
{
throw new System.Exception("StringView's Constructor OutOfBound");
}
} public int IndexOf(char c, int start = )
{
fixed (char* p = this.str)
{
for (int i = start; i < length; ++i)
{
if (p[this.begin + i] == c) return i;
}
} return -;
} private static bool ArrayContains(char[] array, char c)
{
int length = array.Length;
fixed (char* p = array)
{
for (int i = ; i < length; ++i)
if (p[i] == c) return true;
} return false;
} public int IndexOf(char[] array, int start = )
{
if (array.Length == ) return this.IndexOf(array[], start); fixed (char* p = this.str)
{
for (int i = start; i < length; ++i)
{
if (ArrayContains(array, p[this.begin + i])) return i;
}
} return -;
} public int IndexOf(string s, int start = )
{
int s1_length = this.str.Length;
int s2_length = s.Length;
fixed (char* p1 = this.str)
{
fixed (char* p2 = s)
{
int index = this.IndexOf(p2[], start);
while (index >= )
{
if (s2_length > s1_length - this.begin - index)
return -;
bool match = true;
for (int i = ; i < s2_length; ++i)
{
if (p1[this.begin + index + i] != p2[i]) { match = false; break; }
}
if (match) return index; index = this.IndexOf(p2[], index + );
}
return -;
}
}
} public unsafe char this[int index]
{
get
{
if (index < || index >= this.length)
{
throw new System.Exception("StringView's Index OutOfBound");
} fixed (char* p = this.str)
{
return p[this.begin + index];
}
}
} public StringView SubString(int begin)
{
return this.SubString(begin, this.length - begin);
} public StringView SubString(int begin, int length)
{
return new StringView(this.str, this.begin + begin, length);
} public List<StringView> Split(char split, List<StringView> array)
{
array.Clear(); int index = ;
int pos1 = , pos2 = ;
pos2 = this.IndexOf(split);
while (pos2 > && pos2 < this.length)
{
array.Add(new StringView(str, this.begin + pos1, pos2 - pos1));
pos1 = pos2 + ;
pos2 = this.IndexOf(split, pos1);
++index;
}
if (pos1 != this.length) array.Add(new StringView(str, this.begin + pos1, this.length - pos1)); return array;
} public override bool Equals(object obj)
{
if (obj is StringView)
{
StringView v = (StringView)obj;
return this.Equals(v);
}
return false;
} public bool Equals(StringView v)
{
if (v.Length != this.Length) return false;
for (int i = ; i < this.Length; ++i)
{
if (this[i] != v[i]) return false;
}
return true;
} internal static int CombineHashCodes(int h1, int h2)
{
return (((h1 << ) + h1) ^ h2);
} public override int GetHashCode()
{
int hash_code = ;
for (int i = ; i < this.length; ++i)
{
hash_code = CombineHashCodes(hash_code, this[i].GetHashCode());
}
return hash_code;
} public int Length { get { return this.length; } } public override string ToString()
{
return this.str.Substring(begin, length);
} public string GetRawString() { return this.str; }
public int GetBegin() { return this.begin; } private string str;
private int begin;
private int length;
}
为了方便替换String, 很多接口都保持了一致. 目前这个版本只是满足我自己的需求, 以后可以考虑继续完善添加String的函数进来.
之前说的IndexOf
也比较耗, 因为String
的索引器
会带有边界检测, 而IndexOf
一直在用索引器, 所以个人感觉是不太合适的, 所以我的StringView
一直在用指针….
PS: 修改之后的纯text parse, 速度比json parse的速度快一倍以上, 性能还不错, 实际上还有提升的空间
PS: 现在比较完整的StringView已经上传至github, https://github.com/egmkang/StringView 添加了ToInt64
, StringBuilder.Append
支持
C#里面滥用String造成的性能问题的更多相关文章
- 从.Net版本演变看String和StringBuild性能之争
在C#中string关键字的映射实际上指向.NET基类System.String.System.String是一个功能非常强大且用途非常广泛的基类,所以我们在用C#string的时候实际就是在用.NE ...
- 从.Net版本演变看String和StringBuilder性能之争
在C#中string关键字的映射实际上指向.NET基类System.String.System.String是一个功能非常强大且用途非常广泛的基类,所以我们在用C#string的时候实际就是在用.NE ...
- JVM系列之:String.intern的性能
目录 简介 String.intern和G1字符串去重的区别 String.intern的性能 举个例子 简介 String对象有个特殊的StringTable字符串常量池,为了减少Heap中生成的字 ...
- string insert 的性能分析
有这样一个网络传输包. 前端有个固定的包头,包含了后面传输body的长度信息. 在有拷贝的前提下,我们选用什么性能比较高呢? 方案一 复用data_buffer str ...
- Java中String连接性能的分析【转】
[转]http://www.blogjava.net/javagrass/archive/2010/01/24/310650.html 总结:如果String的数量小于4(不含4),使用String. ...
- Java中String连接性能的分析
总结:如果String的数量小于4(不含4),使用String.concat()来连接String,否则首先计算最终结果的长度,再用该长度来创建一个StringBuilder,最后使用这个String ...
- 也谈string.Join和StringBuilder的性能比较
前几天在园子里面看到一篇讲StringBuilder性能的文章.文章里面给出了一个测试用例,比较StringBuilder.AppendJoin和String.Join的性能.根据该测试结果,&quo ...
- java中String的相等比较
首先贴出测试用例: package test; import org.junit.Test; /** * Created by Administrator on 2015/9/16. * */ pub ...
- java中的String设计原理
首先,必须强调一点:String Pool不是在堆区,也不是在栈区,而是存在于方法区(Method Area) 解析: String Pool是常量池(Constant Pool)中的一块. 我们知 ...
随机推荐
- 用百度地图API分析打交通大数据
百度地图API, 文档不全,例子不细致. 在网上还没有太多有用的例子.比如说下面几个需求的解决方案就找不到: 1. 如何用百度地图API查询一个地点的经纬度. 2. 如何用百度地图通过一个经纬度查询商 ...
- AIOps背景/所应具备技术能力分析(上)
本文篇幅较长,分为上,中,下,三个部分进行连载.内容分别为:AIOps 背景/所应具备技术能力分析(上),AIOps 常见的误解(中),挑战及建议(下). 前言 我大概是 5,6 年前开始接触 ITO ...
- spring4笔记----报错publicid systemid之间要有空格的解决方法
<?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www. ...
- wifi破解基础及工具的使用
cdlinux学习,WiFi破解 cdlinux下载.vm安装 cdlinux下载 密码:vxao - 注意:cdlinux必须是在连接网卡的情况下,才能使用 水滴的使用 抓包.跑包 选择信号强度高, ...
- 【公众号系列】SAP S/4 HANA 1809请查收
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[公众号系列]SAP S/4 HANA 1809 ...
- Linux 系统出现电流音解决方案
迫于Windows 系统最近的各种故障,今天脱坑换了openSUSE Linux ,在上网途中播放视频时偶尔会出现电流音,虽然影响不大,但是还是进行了一些排查. 通过观察电流音出现时的系统负载的波段, ...
- 聚类——WKFCM
聚类——认识WKFCM算法 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 参考文献:Shen H, Yang J, Wang S, et al. At ...
- 转:Java中的String,StringBuilder,StringBuffer三者的区别
最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBuffer这三个类之间有什么区别呢,自己从网上搜索了一些资料,有所了解了之后在这里整理一下, ...
- jquery中prop()和attr()用法
jquery1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. 大家都知道有的浏览器只要写disabled,checked就可以了,而有的 ...
- 设计模式のFlyweight(享元模式)----结构模式
一.产生背景 享元模式:它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件:它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件.通常物件中的部分状态是可以分享.常见做 ...