编写目的

在频繁的字符串拼接中,为了提升程序的性能,我们往往会用StringBuilder代替String+=String这样的操作;

而我在实际编码中发现,大部分情况下我用到的只是StringBuilder的Append方法;

一些极端的情况下,我希望我的程序性能更高,这时从StringBuilder入手是一个不错的主意;

所以我希望用一种简单的方案代替StringBuilder,我将这个方案命名为QuickStringWriter;

 

  方案定义

对于StringBuilder来说他除了Append之外还会有更多的方法,比如Insert,AppendFormat等

QuickStringWriter这个方案,仅仅是用来代替简单的字符串+=这样的操作,所以我不会考虑他们,只需要重新实现Append,并让他们比StringBuilder更快

 

  初步设计

class QuickStringWriter : IDisposable
{
    public QuickStringWriter Append(bool val);
    public QuickStringWriter Append(byte val);
    public QuickStringWriter Append(char val);
    public QuickStringWriter Append(DateTime val);
    public QuickStringWriter Append(DateTime val, string format);
    public QuickStringWriter Append(decimal val);
    public QuickStringWriter Append(double val);
    public QuickStringWriter Append(Guid val);
    public QuickStringWriter Append(Guid val, string format);
    public QuickStringWriter Append(short val);
    public QuickStringWriter Append(int val);
    public QuickStringWriter Append(long val);
    public QuickStringWriter Append(sbyte val);
    public QuickStringWriter Append(float val);
    public QuickStringWriter Append(string val);
    public QuickStringWriter Append(ushort val);
    public QuickStringWriter Append(uint val);
    public QuickStringWriter Append(ulong val);
    public QuickStringWriter Clear();
    void Dispose();
    string ToString();
}

  结构

QuickStringWriter将使用一个Char数组作为缓冲区(Buff)

使用一个属性Position作为当前字符位置,或者说是当前字符数

重写ToString方法,将当前缓冲区中的内容,从0到Position转为string对象输出

char[] Buff;
int Position;

public override string ToString()
{
    return new string(Buff, 0, Position);
}

  设置缓冲区

既然有缓冲区,那么就要考虑缓冲区不足时的处理

我设计2个方法解决这个问题

//设置缓冲区容量
void SetCapacity(int capacity)
{
    if (capacity > Buff.Length)
    {
        if (capacity > 6000 * 10000)   //6000W
        {
            throw new OutOfMemoryException("QuickStringWriter容量不能超过6000万个字符");
        }
    }
    var newbuff = new char[capacity];
    Array.Copy(Buff, 0, newbuff, 0, Math.Min(Position, capacity));
    Buff = newbuff;
    Position = Math.Min(Position, Buff.Length);
}
//翻倍空间
void ToDouble()
{
    SetCapacity(Math.Min(Buff.Length * 2, 10 * 10000));
}

 

第一个方法SetCapacity,我预留了一个缩小当前缓冲区的处理,虽然现在不会使用

第二个方法就是翻倍缓冲区,这里也是有个条件的,如果当前缓冲区大于5W,最多一次也只能扩容10W字符的容量

//当容量不足的时候,尝试翻倍空间
void Try()
{
    if (Position >= Buff.Length)
    {
        ToDouble();
    }
}
//测试剩余空间大小,如果不足,则扩展至可用大小后再翻倍
void Check(int count)
{
    var pre = Position + count;
    if (pre >= Buff.Length)
    {
        SetCapacity(pre * 2);
    }
}

 

这里还需要2个方法可以方面的调用 

比如在追加单个字符的时候可以调用Try

在追加指定长度字符之前可以调用Check

 

  性能

在性能上,我只要考虑每一个方法的性能都能快StringBuilder就可以了,这点其实并不是非常困难

public QuickStringWriter Append(Boolean val)
{
    if (val)
    {
        Check(4);
        Buff[Position++] = 't';
        Buff[Position++] = 'r';
        Buff[Position++] = 'u';
        Buff[Position++] = 'e';
    }
    else
    {
        Check(5);
        Buff[Position++] = 'f';
        Buff[Position++] = 'a';
        Buff[Position++] = 'l';
        Buff[Position++] = 's';
        Buff[Position++] = 'e';
    }
    return this;
}
bool类型处理

相关文章: