String.Replace()与StringBuilder.Replace()

Dus*_*vis 73 .net c# replace .net-4.0

我有一个字符串,我需要用字典中的值替换标记.它必须尽可能高效.使用string.replace执行循环只会消耗内存(字符串是不可变的,请记住).StringBuilder.Replace()会更好,因为它是用于字符串操作的吗?

我希望避免花费RegEx,但如果这样做会更有效率那么就这样吧.

注意:我不关心代码复杂性,只关心它运行的速度和消耗的内存.

平均统计数据:长度为255-1024个字符,字典中为15-30个字符.

Dus*_*vis 68

使用以下代码使用RedGate Profiler

class Program
    {
        static string data = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
        static Dictionary<string, string> values;

        static void Main(string[] args)
        {
            Console.WriteLine("Data length: " + data.Length);
            values = new Dictionary<string, string>()
            {
                { "ab", "aa" },
                { "jk", "jj" },
                { "lm", "ll" },
                { "yz", "zz" },
                { "ef", "ff" },
                { "st", "uu" },
                { "op", "pp" },
                { "x", "y" }
            };

            StringReplace(data);
            StringBuilderReplace1(data);
            StringBuilderReplace2(new StringBuilder(data, data.Length * 2));

            Console.ReadKey();
        }

        private static void StringReplace(string data)
        {
            foreach(string k in values.Keys)
            {
                data = data.Replace(k, values[k]);
            }
        }

        private static void StringBuilderReplace1(string data)
        {
            StringBuilder sb = new StringBuilder(data, data.Length * 2);
            foreach (string k in values.Keys)
            {
                sb.Replace(k, values[k]);
            }
        }

        private static void StringBuilderReplace2(StringBuilder data)
        {
            foreach (string k in values.Keys)
            {
                data.Replace(k, values[k]);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)
  • String.Replace = 5.843ms
  • StringBuilder.Replace#1 = 4.059ms
  • Stringbuilder.Replace#2 = 0.461ms

字符串长度= 1456

stringbuilder#1在方法中创建了stringbuilder,而#2则没有,所以性能差异最终会变得相同,因为你只是将该工作移出方法.如果你从stringbuilder而不是字符串开始,那么#2可能是另一种方式.

至于内存,使用RedGateMemory分析器,在进入很多替换操作之前没有什么可担心的,其中stringbuilder将在整体上获胜.

  • @Dai - (延迟回复) - 如答案中所述,探查器仅测量实际功能的经过时间.由于替换#2中的stringbuilder声明在函数外部,因此构造时间不包括在经过的时间中. (7认同)
  • 所以你是说 StringBuilderReplace1 89% 的替换时间只是初始化 StringBuilder 实例?大约只有 11%(4.059 中的 0.461)时间用于进行键替换,如 StringBuilderReplace2 中所示?如果是这样...我会分配一个 StringBuilder 缓冲区,并限制使用现有实例进行批处理的一定程度的并行性。现在的问题是... StringBuilder.ToString 添加到时间中的是什么呢?因为,公平地说,您的目标输出毕竟是一个字符串,并且只有第一个方法实际上生成一个字符串。 (3认同)

RMD*_*RMD 9

这可能有所帮助:

http://blogs.msdn.com/b/debuggingtoolbox/archive/2008/04/02/comparing-regex-replace-string-replace-and-stringbuilder-replace-which-has-better-performance.aspx

简短的回答似乎是String.Replace更快,尽管它可能会对您的内存占用/垃圾收集开销产生更大的影响.


And*_*rei 6

是的,StringBuilder会给你速度和内存的增益(主要是因为每次你用它StringBuilder来操作它都不会创建一个字符串的实例 - 总是使用相同的对象操作).这是一个MSDN链接,其中包含一些详细信息.


Hen*_*man 5

stringbuilder.replace会比String.Replace更好吗?

是的,好多了.如果你可以估计新字符串的上限(看起来你可以),那么它可能足够快.

当你创建它时:

  var sb = new StringBuilder(inputString, pessimisticEstimate);
Run Code Online (Sandbox Code Playgroud)

然后StringBuilder将不必重新分配其缓冲区.