有人可以解释为什么这段代码运行这么长时间(即> 24小时): 行数为5000,而列数为2000(即大约10米的循环)。
有更好的方法吗????
for (int i = 0; i < m.rows; i++)
{
for (int j = 0; j < m.cols; j++)
{
textToWrite += m[i, j].ToString() + ",";
}
//remove the final comma.
textToWrite = textToWrite.Substring(0,textToWrite.Length-2);
textToWrite += Environment.NewLine;
}
答案 0 :(得分:6)
是的,+=
运营商效率不高。请改用StringBuilder
。
在.NET框架中,字符串是不可变的,这意味着它无法在适当的位置进行修改。这意味着+=
运算符必须每次都创建一个新字符串,这意味着分配内存,复制现有字符串的值并将其写入新位置。一两个连接都可以,但只要你把它放在循环中就需要使用替代方法。
http://support.microsoft.com/kb/306822
使用以下代码可以看到性能大幅提升:
var textToWriteBuilder = new StringBuilder();
for (int i = 0; i < m.rows; i++)
{
for (int j = 0; j < m.cols; j++)
{
textToWriteBuilder.Append(m[i, j].ToString() + ",");
}
// I've modified the logic on the following line, I assume you want to
// concatenate the value instead of overwriting it as you do in your question.
textToWriteBuilder.Append(textToWriteBuilder.Substring(0, textToWriteBuilder.Length - 2));
textToWriteBuilder.Append(Environment.NewLine);
}
string textToWrite = textToWriteBuilder.ToString();
答案 1 :(得分:2)
我看到的最大问题是你将textToWrite用作string
。
由于字符串是不可变的,因此每次更改字符串时,必须保留从先前版本复制的新内存。
更有效的方法是使用专为此类场景设计的StringBuilder
类。例如:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < m.rows; i++)
{
for (int j = 0; j < m.cols; j++)
{
sb.Append(m[i, j].ToString());
if(j < m.cols - 1) // don't add a comma on the last element
{
sb.Append(",");
}
}
sb.AppendLine();
}
答案 2 :(得分:2)
你的代码花了这么长时间,因为你要附加字符串,随时创建数千个新的临时字符串。内存管理器需要为这些字符串找到内存(这会增加内存需求,因为它们会变长),并且操作会将到目前为止的字符(每次迭代的次数增加)复制到最新的字符串。
替代方法是使用单个StringBuilder
,您可以在其上调用Append()
以更有效地追加,最后,ToString()
当您完成获取最终的字符串时想用。
答案 3 :(得分:2)
因为你创造了大量的字符串。
你应该使用StringBuilder。
StringBuilder sb = new StringBuildeR();
for (int i = 0; i < m.rows; i++)
{
bool first = true;
for (int j = 0; j < m.cols; j++)
{
sb.Append(m[i, j]);
if (first)
{
first = false;
}
else
{
sb.Append(",");
}
}
sb.AppendLine();
}
string output = sb.ToString();
答案 4 :(得分:1)
假设textToWrite
是String
,您应该使用StringBuilder
代替String
。 StringBuilder
是不可变的,添加小部件非常无效。
理想情况下,您会以合理的尺寸初始化{{1}}(请参阅doc)。
答案 5 :(得分:1)
使用StringBuilder
代替数百万个连接。
如果连接2个字符串,这意味着系统会分配新的内存来包含它们,然后将它们都复制进去。很多大内存分配和复制操作变得非常快。
StringBuilder
所做的是通过分配'提前'来极大地减少这种情况,因此只需要将缓冲区增长几次并将其复制进去,从而消除循环中最慢的因素。
答案 6 :(得分:1)
假设矩阵的大小为MxM且具有N个元素。您正在以一种在迭代次数中采用 O(N^2)
(或O(M^4)
)的方式构建字符串。每个操作必须复制已存在的内容。问题是不某些常量因素开销,如临时字符串。
使用StringBuilder。
字符串连接对于少量连接字符串更有效。对于动态数量的字符串,请使用StringBuilder。
答案 7 :(得分:0)
运行这么长时间的原因是因为您使用字符串连接来创建字符串。对于每次迭代,它会将整个字符串复制到一个新字符串,因此最后您将复制的字符串最多可以添加到最终字符串的数百万倍。
使用StringBuilder
创建字符串:
StringBuilder textToWrite = new StringBuilder();
for (int i = 0; i < m.rows; i++)
{
for (int j = 0; j < m.cols; j++)
{
if (j > 0) textToWrite.Append(',');
textToWrite.Append(m[i, j]);
}
textToWrite.AppendLine();
}