【问题标题】:What's causing this spike in time of string concatenation?是什么导致字符串连接时间出现这种峰值?
【发布时间】:2013-11-15 05:53:35
【问题描述】:

所以出于好奇和无聊,我一直在玩弄基准测试Shlemiel the painter's algorithm。我从一个空白字符串开始,在 1000 个空格中创建了另一个,然后开始将一个添加到另一个,使用普通的低效字符串连接,计算每次花费的时间。

string s1 = "";
string s2 = "";
while (s2.Length < 1000)
{
    s2 += " ";
}

while (true)
{
    Stopwatch sw = Stopwatch.StartNew();
    s1 += s2;
    sw.Stop();

    Console.WriteLine(" {0}| {1}", s1.Length, sw.ElapsedMilliseconds);
}

正如预期的那样,字符串越长,连接所需的时间就越长(这比我预期的影响要小得多,但这是另一天的另一个问题)。然而,令人惊讶的是,所用时间的持续峰值。每六个连接所用的时间大约是前五个连接的两到三倍。

 Length     | Time (ms)
 -----------------------
 32250000   | 117
 32251000   | 44
 32252000   | 31
 32253000   | 30
 32254000   | 30
 32255000   | 32
 32256000   | 129
 32257000   | 35
 32258000   | 43
 32259000   | 34
 32260000   | 30
 32261000   | 29
 32262000   | 107
 32263000   | 47
 32264000   | 29
 32265000   | 30
 32266000   | 31
 32267000   | 29
 32268000   | 110
 32269000   | 46
 32270000   | 31
 32271000   | 30
 32272000   | 30
 32273000   | 30
 32274000   | 113

这些样本是从字符串开始变得非常大的时候开始的,但模式从一开始就成立。大多数情况下,前一千个左右的样本太小而无法注意到这种模式,但在 1.8k 左右它是可识别的。

我的第一个假设是,在幕后,字符被存储在某种 ArrayList/vector 类型的交易中,一旦填满,它的大小就会翻倍,但当我想得更多时,这不合适 - 如果在这种情况下,峰值会以指数周期出现,而不是线性出现。

所以,简而言之:这到底是怎么回事?

【问题讨论】:

  • 可能是垃圾回收。如果您真的感兴趣,请尝试运行分析器;恐怕我们不能不猜。
  • GC 是否足够一致,可以恰好每第六次迭代发生一次(假设它对于整个数据集都是一致的)?

标签: c# performance string-concatenation stopwatch


【解决方案1】:

创建字符串并丢弃它们会产生垃圾。一旦您使用了一定数量的内存,就会发生垃圾收集并暂停您的进程。由于您的进程中没有其他任何事情发生,并且您总是使字符串长度相同,因此 GC 总是同时发生(每 6 次运行)。

为避免对您的计时产生这种影响,请在每次运行开始计时之前致电GC.Collect

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    相关资源
    最近更新 更多