string.format()是否应该多用?

string.format()是否应该多用?

前一阵子,项目中的一个页面每秒只能处理300次,而这个页面的逻辑也不复杂,就是根据条件拼出一个字串然后输出。开始以为这里面逻辑太复杂,所以有问题。不过后面发现了vs里面带了性能分析工具,于是抱着试试看的想法,作了一下性能分析。最后的结果让人大吃一惊:string.format这个操作竟然用掉了一半的时间,为啥它会这么费时间呢?为了真相,我用.net reflector查看了string的实现:

public static string Format(IFormatProvider provider, string format, params object[] args)
{
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }
    StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
    builder.AppendFormat(provider, format, args);
    return builder.ToString();
}

很让人吃惊,string.format竟然是调用了StringBuilder的AppendFormat来实现的。再继续根下去(这个源码只是通过IL得来的,可能和原始的不太一样,但是差不多了),注意里面的红色的那句:

public StringBuilder AppendFormat(IFormatProvider provider, string format, params object[] args)
{
    int num3;
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }
    char[] chArray = format.ToCharArray(0, format.Length);
    int index = 0;
    int length = chArray.Length;
    char ch = '/0';
    ICustomFormatter formatter = null;
    if (provider != null)
    {
        formatter = (ICustomFormatter) provider.GetFormat(typeof(ICustomFormatter));
    }
Label_004E:
    num3 = index;
    int num4 = index;
    while (index < length)
    {
        ch = chArray[index];
        index++;
        if (ch == '}')
        {
            if ((index < length) && (chArray[index] == '}'))
            {
                index++;
            }
            else
            {
                FormatError();
            }
        }
        if (ch == '{')
        {
            if ((index < length) && (chArray[index] == '{'))
            {
                index++;
            }
            else
            {
                index--;
                break;
            }
        }
        chArray[num4++] = ch;
    }
    if (num4 > num3)
    {
        this.Append(chArray, num3, num4 - num3);
    }
    if (index == length)
    {
        return this;
    }
    index++;
    if (((index == length) || ((ch = chArray[index]) < '0')) || (ch > '9'))
    {
        FormatError();
    }
    int num5 = 0;
    do
    {
        num5 = ((num5 * 10) + ch) - 0x30;
        index++;
        if (index == length)
        {
            FormatError();
        }
        ch = chArray[index];
    }
    while (((ch >= '0') && (ch <= '9')) && (num5 < 0xf4240));
    if (num5 >= args.Length)
    {
        throw new FormatException(Environment.GetResourceString("Format_IndexOutOfRange"));
    }
    while ((index < length) && ((ch = chArray[index]) == ' '))
    {
        index++;
    }
    bool flag = false;
    int num6 = 0;
    if (ch == ',')
    {
        index++;
        while ((index < length) && (chArray[index] == ' '))
        {
            index++;
        }
        if (index == length)
        {
            FormatError();
        }
        ch = chArray[index];
        if (ch == '-')
        {
            flag = true;
            index++;
            if (index == length)
            {
                FormatError();
            }
            ch = chArray[index];
        }
        if ((ch < '0') || (ch > '9'))
        {
            FormatError();
        }
        do
        {
            num6 = ((num6 * 10) + ch) - 0x30;
            index++;
            if (index == length)
            {
                FormatError();
            }
            ch = chArray[index];
        }
        while (((ch >= '0') && (ch <= '9')) && (num6 < 0xf4240));
    }
    while ((index < length) && ((ch = chArray[index]) == ' '))
    {
        index++;
    }
    object arg = args[num5];
    string str = null;
    if (ch == ':')
    {
        index++;
        num3 = index;
        num4 = index;
        while (true)
        {
            if (index == length)
            {
                FormatError();
            }
            ch = chArray[index];
            index++;
            switch (ch)
            {
                case '{':
                    if ((index < length) && (chArray[index] == '{'))
                    {
                        index++;
                    }
                    else
                    {
                        FormatError();
                    }
                    break;

                case '}':
                    if ((index < length) && (chArray[index] == '}'))
                    {
                        index++;
                    }
                    else
                    {
                        index--;
                        if (num4 > num3)
                        {
                            str = new string(chArray, num3, num4 - num3);
                        }
                        goto Label_0253;
                    }
                    break;
            }
            chArray[num4++] = ch;
        }
    }
Label_0253:
    if (ch != '}')
    {
        FormatError();
    }
    index++;
    string str2 = null;
    if (formatter != null)
    {
        str2 = formatter.Format(str, arg, provider);
    }
    if (str2 == null)
    {
        if (arg is IFormattable)
        {
            str2 = ((IFormattable) arg).ToString(str, provider);
        }
        else if (arg != null)
        {
            str2 = arg.ToString();
        }
    }
    if (str2 == null)
    {
        str2 = string.Empty;
    }
    int repeatCount = num6 - str2.Length;
    if (!flag && (repeatCount > 0))
    {
        this.Append(' ', repeatCount);
    }
    this.Append(str2);
    if (flag && (repeatCount > 0))
    {
        this.Append(' ', repeatCount);
    }
    goto Label_004E;
}

发现里面会有new string,这时候会有新的内存分配出现,也就是说string.format会产生很多临时的string对象,这个会费时间,同时也会使GC的工作量增加.既然这里面调用了stringbuilder来实现的,那为啥不直接调用stringbuilder.append来实现。于是我就把原来的实现改成了stringbuilder的append,同时设置它初始容量为我们预期的大小,通过测试,这部分的性能提高了十倍。于是性能问题解决了。

最后,我觉得如果程序的性能很重要,而在这里面又经常有string.format的时候,还是改用stringbuilder.append来实现,虽然麻烦一些,代码也不好看,但是效果还是会很明显的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值