连接字符串最有效的方法?

c# .net string optimization

189066 观看

17回复

1321 作者的声誉

连接字符串的最有效方法是什么?

作者: jimmij 的来源 发布者: 2008 年 8 月 21 日

回应 17


2

13938 作者的声誉

最有效的是使用StringBuilder,如下所示:

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@jonezy:如果你有几个小东西,String.Concat就可以了。但是,如果你连接数兆字节的数据,你的程序可能会坦克。

作者: TheSmurf 发布者: 2008 年 8 月 21 日

142

3529 作者的声誉

决定

StringBuilder.Append()方法比使用+运算符要好得多。但我发现,当执行1000个或更少的连接时,String.Join()效率甚至更高StringBuilder

StringBuilder sb = new StringBuilder();
sb.Append(someString);

唯一的问题String.Join是您必须使用公共分隔符连接字符串。(编辑:)正如@ryanversaw指出的那样,你可以制作分隔符string.Empty。

string key = String.Join("_", new String[] 
{ "Customers_Contacts", customerID, database, SessionID });
作者: TheEmirOfGroofunkistan 发布者: 2008 年 8 月 21 日

0

9595 作者的声誉

对于两个字符串,您绝对不想使用StringBuilder。有一些阈值,高于该阈值,StringBuilder开销小于分配多个字符串的开销。

因此,对于更多2-3个字符串,请使用DannySmurf的代码。否则,只需使用+运算符即可。

作者: Nick 发布者: 2008 年 8 月 21 日

52

19053 作者的声誉

来自Chinh Do - StringBuilder并不总是更快

经验法则

  • 连接三个或更少的动态字符串值时,请使用传统的字符串连接。

  • 连接三个以上的动态字符串值时,请使用StringBuilder。

  • 从多个字符串文字构建一个大字符串时,请使用@ string literal或inline +运算符。

大多数时候StringBuilder是你最好的选择,但有一些案例如该帖子所示,你至少应该考虑每种情况。

作者: palehorse 发布者: 2008 年 8 月 21 日

0

2202 作者的声誉

这取决于代码。StringBuilder通常效率更高,但是如果你只连接几个字符串并在一行中完成所有操作,代码优化可能会为你处理它。考虑代码的外观也很重要:对于较大的集合,StringBuilder将使其更易于阅读,对于较小的集合,StringBuilder只会添加不必要的混乱。

作者: Jon Dewees 发布者: 2008 年 8 月 21 日

11

4428 作者的声誉

如果你在一个循环中操作,StringBuilder可能是要走的路; 它可以节省您定期创建新字符串的开销。但是,在只运行一次的代码中,String.Concat可能没问题。

然而,Rico Mariani(.NET优化大师)做了一个测验,他在最后说,在大多数情况下,他推荐String.Format。

作者: Adam V 发布者: 2008 年 8 月 21 日

261

15930 作者的声誉

.NET性能大师Rico Mariani一篇关于这个主题的文章。它并不像人们怀疑的那么简单。基本建议如下:

如果您的模式如下:

x = f1(...) + f2(...) + f3(...) + f4(...)

这是一个concat,它很活泼,StringBuilder可能无济于事。

如果您的模式如下:

if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)

那么你可能想要StringBuilder。

另一篇支持这一说法的文章来自Eric Lippert,他+在文章中详细描述了对一行连接进行的优化。

作者: Lee 发布者: 2008 年 8 月 21 日

6

30408 作者的声誉

从这篇MSDN文章

在时间和内存中创建StringBuilder对象都会产生一些开销。在具有快速内存的机器上,如果您正在执行大约五个操作,则StringBuilder变得值得。根据经验,我会说10个或更多字符串操作是任何机器上的开销的理由,即使是较慢的。

因此,如果您信任MSDN,请使用StringBuilder,如果您必须执行超过10个字符串操作/连接 - 否则使用'+'的简单字符串连接就可以了。

作者: JohnIdol 发布者: 2008 年 10 月 2 日

1

1354 作者的声誉

这实际上取决于您的使用模式。string.Join,string,Concat和string.Format之间的详细基准可以在这里找到:String.Format不适合密集记录

(这实际上是我给这个问题的答案)

作者: Liran 发布者: 2011 年 5 月 31 日

73

28598 作者的声誉

有6种类型的字符串连接:

  1. 使用加号(+)符号。
  2. string.Concat()
  3. string.Join()
  4. string.Format()
  5. string.Append()
  6. StringBuilder

在一个实验中,已经证明,string.Concat()如果单词小于1000(大约)并且如果单词大于1000则StringBuilder应该使用最好的接近方法。

有关更多信息,请查看此站点

string.Join()vs string.Concat()

这里的string.Concat方法相当于带有空分隔符的string.Join方法调用。附加一个空字符串很快,但不这样做更快,所以string.Concat方法在这里会更好。

作者: Mr_Green 发布者: 2012 年 9 月 4 日

4

6346 作者的声誉

+如果要连接字符串文字,指出它应该使用运算符也很重要。

使用+运算符连接字符串文字或字符串常量时,编译器会创建一个字符串。没有运行时连接发生。

如何:连接多个字符串(C#编程指南)

作者: talles 发布者: 2013 年 10 月 14 日

1

133 作者的声誉

System.String是不可变的。当我们修改字符串变量的值时,会将新内存分配给新值并释放先前的内存分配。System.StringBuilder被设计为具有可变字符串的概念,其中可以执行各种操作而无需为修改的字符串分配单独的存储器位置。

作者: Dhibi_Mohanned 发布者: 2014 年 4 月 24 日

5

145 作者的声誉

添加到其他答案,请记住,StringBuilder可以被告知要分配的初始内存量

所述容量参数定义可被存储在由当前实例所分配的存储器的字符的最大数目。其值分配给Capacity属性。如果要存储在当前实例中的字符数超过此容量值,则StringBuilder对象会分配额外的内存来存储它们。

如果capacity为零,则使用特定于实现的默认容量。

重复附加到尚未预先分配的StringBuilder可能会导致大量不必要的分配,就像重复连接常规字符串一样。

如果您知道最后一个字符串将持续多长时间,可以轻松地计算它,或者可以对常见情况进行有根据的猜测(分配太多并不一定是坏事),您应该将这些信息提供给构造函数或者容量财产。特别是在运行性能测试时,将StringBuilder与其他方法(如String.Concat)进行比较,这些方法在内部执行相同的操作。您在网上看到的任何测试都没有包含StringBuilder在其比较中的预分配是错误的。

如果你不能对大小做任何猜测,你可能正在编写一个实用函数,它应该有自己的可选参数来控制预分配。

作者: DBN 发布者: 2014 年 10 月 31 日

2

39 作者的声誉

试试这两段代码,你就会找到解决方案。

 static void Main(string[] args)
    {
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < 10000000; i++)
        {
            s.Append( i.ToString());
        }
        Console.Write("End");
        Console.Read();
    }

VS

static void Main(string[] args)
    {
        string s = "";
        for (int i = 0; i < 10000000; i++)
        {
            s += i.ToString();
        }
        Console.Write("End");
        Console.Read();
    }

你会发现第一个代码将很快结束,内存将会很好。

第二个代码可能是内存可以正常,但需要更长时间......更长时间。因此,如果您有许多用户的应用程序并且您需要速度,请使用1st。如果你有一个短期一个用户应用程序的应用程序,也许你可以使用两者或第二个对开发人员更“自然”。

干杯。

作者: Eduardo Mass 发布者: 2016 年 1 月 1 日

3

115 作者的声誉

以下可能是连接多个字符串的另一种替代解决方案。

String str1 = "sometext";
string str2 = "some other text";

string afterConcate = $"{str1}{str2}";

字符串插值

作者: RP Nainwal 发布者: 2017 年 3 月 28 日

8

9943 作者的声誉

这是我用于大型NLP应用程序十多年来发展最快的方法。我有IEnumerable<T>和其他输入类型的变体,有和没有不同类型的分隔符(CharString),但在这里我展示了将数组中的所有字符串连接成单个字符串,没有分隔符的简单情况 。这里的最新版本是在C#7.NET 4.7上开发和单元测试的。

提高性能有两个关键因素; 首先是预先计算所需的确切总大小。当输入是如此处所示的数组时,此步骤是微不足道的。IEnumerable<T>相反,为了处理,首先要将字符串收集到一个临时数组中以计算总数(该数组需要避免ToString()每个元素调用多次,因为从技术上讲,考虑到副作用的可能性,这样做可能会改变预期的语义一个'字符串连接'操作)。

接下来,给定最终字符串的总分配大小,通过就地构建结果字符串可以获得性能的最大提升。这样做需要(可能是有争议的)暂停新的不变性的技术,该新String的最初被分配为零。除此之外,还有任何此类争议......

...请注意,这是此页面上唯一的批量连接解决方​​案,它完全避免了构造函数的额外轮次分配和复制String

完整代码:

/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
    int i;
    if (rg == null || (i = rg.Length) == 0)
        return String.Empty;

    if (i == 1)
        return rg[0];

    String s, t;
    int cch = 0;
    do
        cch += rg[--i].Length;
    while (i > 0);
    if (cch == 0)
        return String.Empty;

    i = rg.Length;
    fixed (Char* _p = (s = new String(default(Char), cch)))
    {
        Char* pDst = _p + cch;
        do
            if ((t = rg[--i]).Length > 0)
                fixed (Char* pSrc = t)
                    memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
        while (pDst > _p);
    }
    return s;
}

[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);

我应该提一下,这段代码与我自己使用的内容略有不同。在原文中,我从C#调用cpblk IL指令进行实际复制。为了简化和在这里的代码的可移植性,我用P / Invoke 代替了,正如你所看到的。为了在x64上获得最高性能(但可能不是x86),您可能需要使用cpblk方法。memcpy

作者: Glenn Slayden 发布者: 2017 年 11 月 10 日

1

17 作者的声誉

另一种方案:

在循环内部,使用List而不是string。

List<string> lst= new List<string>();

for(int i=0; i<100000; i++){
    ...........
    lst.Add(...);
}
return String.Join("", lst.ToArray());;

它非常快。

作者: asady 发布者: 2018 年 1 月 19 日
32x32