`

StringJoiner 拯救那些性能低下的字符串拼装代码

阅读更多
作者:Bruce(编程的艺术世界)
出处:http://coolcode.cnblogs.com

String
这篇文章是想介绍大家一个小技巧。

我们知道,或者第一天学习C#的时候就认识string类型,然后很快就知道最简单的拼装string的写法:

string s = string.Empty;
s += "Bruce";
s += "Who?";
s += "a guy think sth different...";


这种写法实在是太简单太美好了,因为相比C语言的 strcat 写法,使用C#实在是太幸福了。而且不知道什么时候还支持这种写法:

s += "Bruce" + " Lee";
(我实在不知道什么时候开始支持以上写法,记得.Net2.0是不能这样写的,如果是.Net1.1肯定不行,一定要加括号:

s += ("Bruce" + " Lee");
)

StringBuilder
然而,这种幸福感可能导致初学者不知道StringBuilder的存在,偶尔在其他人的文章上看到StringBuilder,可能也是不了解为什么有“+=”不用,要写上一堆 Append ...

StringBuilder sb = new StringBuilder();
sb.Append("Bruce");
sb.Append("Who?");
sb.Append("a guy think sth different...");


你或许不相信,我估计在企业里从事.Net工作一两年的朋友,还是有人不知道StringBuilder的存在。特别在 Asp.Net 里,不少朋友喜欢用C#拼装一堆前台代码,如Html语句或JavaScript,甚至SQL语句 … 他们无一例外都是使用“+=”来拼接,然后拍拍屁股就走人了,留下几十行,甚至上百行这样的语句。

我们应该知道,使用第一种方式来拼接字符串,无论是从时间或空间的性能来说,都远不如使用StringBuilder。

好孩子看到这里,可能就会赶快回去把自己那段“+=”全换上StringBuilder的 Append方法。先别急,毕竟由方式一向方式二转换是很费时间的,绝对是苦力活,我现在要告诉大家怎么以最快速使方式一的代码性能上升到方式二。



StringJoiner
很简单,把 string s 改成 StringJoiner s 就大功告成。即

StringJoiner s = string.Empty;
s += "Bruce";
s += "Who?";
s += "a guy think sth different...";


咋这么简单就提高性能?忽悠我?

当然不是忽悠大家,也不是玩魔术,文章末会有性能测试数据,有图有真相。

现在让我来揭开 StringJoiner 的面纱,最后你肯定会说:原来这么简单。

StringJoiner 其实是类似装饰者模式,对外隐藏了StringBuilder ,就像魔术师喜欢把一堆道具藏到袖子,以忽悠观众那样。

public class StringJoiner
{
    protected StringBuilder Builder;

    public StringJoiner()
    {
        Builder = new StringBuilder();
    }
}
(把Builder定义成protected ,期待某天可能需要继承StringJoiner 来继续“忽悠观众”)

StringJoiner 是怎么实现刚才的代码?

1.隐式转换

如:

StringJoiner s = string.Empty;


的谜底是:

public static implicit operator StringJoiner(string value)
{
    StringJoiner text = new StringJoiner();
    text.Builder.Append(value);
    return text;
}
(新建一个对象,把赋值转移到 StringBuilder 的Append方法)



2. 重载操作符

如:

s += "Bruce";


的谜底是:

public static StringJoiner operator +(StringJoiner self, string value)
{
    self.Builder.Append(value);
    return self;
}
(实现 StringJoiner 与 string 类型可以通过运算符“+”操作,同样是把字符串交给StringBuilder 的Append方法)

为了更通用,如实现与其他类型连接:

s += 123;
s += 0.314;
s += 'c';


因此,必须重载 StringJoiner + Object

public static StringJoiner operator +(StringJoiner self, object value)
{
    self.Builder.Append(value);
    return self;
}


最后,为了让 StringJoiner 的“忽悠”水平更上一层楼,StringJoiner 的对象必须能够隐式转换成 string 类型:

public static implicit operator string(StringJoiner value)
{
    return value.ToString();
}

public override string ToString()
{
    return this.Builder.ToString();
}


当然,到这一刻 StringJoiner 已经足够了,更彻底的“忽悠”并不是本文的目的。 StringJoiner 并不是想替代string,更不是替代StringBuilder,反而我举脚赞成使用StringBuilder。但如果你想重构一段由“string += ” 带来的惨不忍睹的代码时,用StringJoiner 吧。



性能测试
性能计数器:CodeTimer (XP版)

测试代码(3种不同方法拼装一万次字符串,接着拼装一万次整数,并重复10次以上操作):

static void Main(string[] args)
{
    CodeTimer.Time("", 1, () => { });

    //通过 += 拼装字符串
    CodeTimer.Time("NormalString", 10, () => NormalString());

    //StringJoiner 拼装字符串
    CodeTimer.Time("StringJoiner", 10, () => StringJoiner());

    //StringBuilder 拼装字符串
    CodeTimer.Time("StringBuilder", 10, () => StringBuilder());

    Console.WriteLine("continue...");
    Console.Read();
}

//拼装字符串长度
const int stringLength = 10000;

static void NormalString()
{
    string s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += "A";//拼装字符串
    s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += 1;//拼装整数
    string result = s;
}

static void StringJoiner()
{
    StringJoiner s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += "A";
    s = string.Empty;
    for (int i = 0; i < stringLength; i++)
        s += 1;
    string result = s;
}

static void StringBuilder()
{
    StringBuilder s = new StringBuilder(string.Empty);
    for (int i = 0; i < stringLength; i++)
        s.Append("A");
    s = new StringBuilder(string.Empty);
    for (int i = 0; i < stringLength; i++)
        s.Append(1);
    string result = s.ToString();
}


其中一次测试结果:


NormalString
        Time Elapsed:           667ms
        Time Elapsed (one time):66ms
        CPU time:               671,875,000ns
        CPU time (one time):    67,187,500ns
        Gen 0:                  1908
        Gen 1:                  0
        Gen 2:                  0

StringJoiner
        Time Elapsed:           19ms
        Time Elapsed (one time):1ms
        CPU time:               15,625,000ns
        CPU time (one time):    1,562,500ns
        Gen 0:                  3
        Gen 1:                  0
        Gen 2:                  0

StringBuilder
        Time Elapsed:           19ms
        Time Elapsed (one time):1ms
        CPU time:               15,625,000ns
        CPU time (one time):    1,562,500ns
        Gen 0:                  3
        Gen 1:                  0
        Gen 2:                  0



从上图可以看到,StringJoiner 和 StringBuilder 性能持平,而它们都远远比第一种方法领先。

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    规则字符串转行转列牛X的SQL,非常有价值

    有这条SQL,可将以字符串拼装方式的属性,拆分出来,并加以利用

    JS下高效拼装字符串的几种方法比较与测试代码

    在JavaScript中,高效地拼接字符串是一个重要的性能优化策略,尤其是在处理大量数据时。传统的字符串拼接方式,如使用`+`运算符或者`String.concat()`方法,可能会导致性能下降,因为每次操作都会创建新的字符串对象...

    易语言SQL拼装1.1 链式编程, 拼装SQL方法

    而是难以维护 难以修改.[子文本替换拼装], [字符串拼装].... 这些都用过. 一旦比较长的sql 改懂就比较麻烦。这个类喜欢你能喜欢. 。------------------------------------------------------。这个模块是用之前我...

    Fastest way to build an HTML string(拼装html字符串的最快方法)

    虽然代码逻辑直观,但在JavaScript中,每次字符串连接都会创建一个新的字符串对象,这在处理大量数据时会显著降低性能。 第二种方法是将元素逐个推入数组,然后使用`join()`方法将数组元素组合成一个字符串。相比于...

    XML 解析与拼装工具类

    基于Dom4j的Xml解析与组装项目工具类.

    .NET 性能优化方法总结

    - **1.7.2 拼装字符串**:使用`StringBuilder`而不是直接使用加号进行字符串拼接。 - **1.7.3 避免两次检索集合元素**:如果在循环中多次访问同一个集合元素,应考虑先将其存储在一个局部变量中。 - **1.7.4 避免两...

    .net性能优化宝典

    **1.7.2 拼装字符串** 使用`StringBuilder`进行字符串拼接是提高性能的有效方式。 **1.7.3 避免两次检索集合元素** 在循环中重复检索集合元素会增加不必要的开销。如果需要多次使用某个元素,可以在循环外部先...

    TBM后配套管片拼装机建模及分析

    TBM后配套管片拼装机是一种用于隧道掘进机械(Tunnel Boring Machine, TBM)的配套设备,它主要用于隧道施工中管片的自动拼装。管片是隧道衬砌的重要组成部分,拼装机能够将预制的管片按照设计要求拼装成环状,以...

    .net代码优化总结、[收集].pdf

    1.7.2 拼装字符串:使用StringBuilder替换 "+" 连接字符串。 1.7.3 避免两次检索集合元素:如果已知索引,直接访问,避免二次查找。 1.7.4 避免两次类型转换:一次转换后保存结果,避免重复转换。 1.7.5 字符串容器...

    从高德地图提取规划线路的gps数据路径集合,转换为经纬度的字符串数组集合

    本项目的核心是提取高德地图的规划线路数据,并将其转化为便于处理的经纬度字符串数组集合。这个过程涉及到数据解析、格式转换以及JSON操作等技术。 首先,我们要理解GPS数据的基本构成。GPS数据通常包含经度和纬度...

    Net性能优化方法总结

    - **1.7.2 拼装字符串**:使用`StringBuilder`进行字符串拼接。 - **1.7.3 避免两次检索集合元素**:如果可能,先将集合元素存储在一个局部变量中。 - **1.7.4 避免两次类型转换**:尽量减少不必要的类型转换操作。 ...

    C++源代码单词扫描程序(词法分析)

    C++语言包含了几种类型的记号:标识符,关键字,数(包括整数、浮点数),字符串、注释、特殊符号(分界符)和运算符号等。 (2)打开一个C++源文件,打印出所有以上的记号。 (3)要求应用程序应为Windows界面。 ...

    钢网架结构拼装.doc

    钢网架结构拼装 钢网架结构拼装是指对钢网架结构的组装和连接,包括钢网架螺栓球节点、焊接球节点、焊接钢板节点等。这里我们将对钢网架结构拼装的相关知识点进行详细的介绍。 2.1 材料要求 钢网架结构拼装中使用...

    分离valuelist的sql拼装

    - **字符串连接**:最基础的方法是通过字符串连接函数,如Python中的`join()`或Java中的`StringBuilder`,逐个添加元素到SQL语句中。 - **模板引擎**:使用如Jinja2(Python)或FreeMarker(Java)等模板引擎,...

    python 操作json文件

    解读字符串拼装成json写入文件,方便其他语言解析数据

    php字符串操作常见问题小结

    记得当初学习php的时候听的一句觉得很牛X的话就是:一切程序都是字符串,所谓编程只是让数据像水一样在各个代码页面间流来流去。等我目前工作中也确实发现数据格式是个很难的问题,涉及到数据的组装、拆分和再拼装。...

    SQL语句拼装工具V2

    写java程序时用来拼装sql语句时使用的小工具,在.net 4.0环境下运行。 跟前一版本比较,增加了前缀和空格位置的自定义,并增加了一个配置文件,保存自定义项 例如将 select a, b, c from abc where a like('3') ...

Global site tag (gtag.js) - Google Analytics