StringBuilder.Append Vs StringBuilder.AppendFormat

前端 未结 9 1347
轮回少年
轮回少年 2021-01-31 15:30

I was wondering about StringBuilder and I\'ve got a question that I was hoping the community would be able to explain.

Let\'s just forget about code readability, which o

9条回答
  •  南笙
    南笙 (楼主)
    2021-01-31 16:14

    casperOne is entirely accurate that it depends on the data. However, suppose you're writing this as a class library for 3rd parties to consume - which would you use?

    One option would be to get the best of both worlds - work out how much data you're actually going to have to append, and then use StringBuilder.EnsureCapacity to make sure we only need a single buffer resize.

    If I weren't too bothered though, I'd use Append x3 - it seems "more likely" to be faster, as parsing the string format tokens on every call is clearly make-work.

    Note that I've asked the BCL team for a sort of "cached formatter" which we could create using a format string and then re-use repeatedly. It's crazy that the framework has to parse the format string each time it's used.

    EDIT: Okay, I've edited John's code somewhat for flexibility and added an "AppendWithCapacity" which just works out the necessary capacity first. Here are the results for the different lengths - for length 1 I used 1,000,000 iterations; for all other lengths I used 100,000. (This was just to get sensible running times.) All times are in millis.

    Unfortunately tables don't really work in SO. The lengths were 1, 1000, 10000, 20000

    Times:

    • Append: 162, 475, 7997, 17970
    • AppendFormat: 392, 499, 8541, 18993
    • AppendWithCapacity: 139, 189, 1558, 3085

    So as it happened, I never saw AppendFormat beat Append - but I did see AppendWithCapacity win by a very substantial margin.

    Here's the full code:

    using System;
    using System.Diagnostics;
    using System.Text;
    
    public class StringBuilderTest
    {            
        static void Append(string string1, string string2)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(string1);
            sb.Append("----");
            sb.Append(string2);
        }
    
        static void AppendWithCapacity(string string1, string string2)
        {
            int capacity = string1.Length + string2.Length + 4;
            StringBuilder sb = new StringBuilder(capacity);
            sb.Append(string1);
            sb.Append("----");
            sb.Append(string2);
        }
    
        static void AppendFormat(string string1, string string2)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("{0}----{1}", string1, string2);
        }
    
        static void Main(string[] args)
        {
            int size = int.Parse(args[0]);
            int iterations = int.Parse(args[1]);
            string method = args[2];
    
            Action action;
            switch (method)
            {
                case "Append": action = Append; break;
                case "AppendWithCapacity": action = AppendWithCapacity; break;
                case "AppendFormat": action = AppendFormat; break;
                default: throw new ArgumentException();
            }
    
            string string1 = new string('x', size);
            string string2 = new string('y', size);
    
            // Make sure it's JITted
            action(string1, string2);
            GC.Collect();
    
            Stopwatch sw = Stopwatch.StartNew();
            for (int i=0; i < iterations; i++)
            {
                action(string1, string2);
            }
            sw.Stop();
            Console.WriteLine("Time: {0}ms", (int) sw.ElapsedMilliseconds);
        }
    }
    

提交回复
热议问题