【发布时间】: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