我的代码是在列表中添加约100,000个项目。
如果我添加一个字符串或对象数组,代码几乎立即运行(不到100毫秒),但如果我尝试添加一个结构数组,那么.Add调用只需1.5秒。
使用struct []时为什么会有这样的性能影响?
这是我的结构:
public struct LiteRowInfo
{
public long Position;
public int Length;
public int Field;
public int Row;
public LiteRowInfo(long position, int length, int field, int row)
{
this.Position = position;
this.Length = length;
this.Field = field;
this.Row = row;
}
}
编辑2:字符串方法的性能比结构的性能快: 我很欣赏这些评论,看起来似乎还有额外的开销来创建自己的结构。我想我会创建2个单独的列表来存储位置和长度以提高性能。
private void Test()
{
Stopwatch watch = new Stopwatch();
watch.Start();
List<LiteRowInfo[]> structList = new List<LiteRowInfo[]>();
for (int i = 0; i < 100000; i++)
{
LiteRowInfo[] info = new LiteRowInfo[20];
for (int x = 0; x < 20; x++)
{
LiteRowInfo row;
row.Length = x;
row.Position = (long)i;
info[x] = row;
}
structList.Add(info);
}
Debug.Print(watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
List<string[]> stringList = new List<string[]>();
for (int i = 0; i < 100000; i++)
{
string[] info = new string[20];
for (int x = 0; x < 20; x++)
{
info[x] = "String";
}
stringList.Add(info);
}
Debug.Print(watch.ElapsedMilliseconds.ToString());
}
编辑:以下是所有相关代码: 注意:如果我只注释掉pos.Add(rowInfo); line,性能类似于string []或int []。
private void executeSqlStream()
{
List<LiteRowInfo[]> pos = new List<LiteRowInfo[]>();
long currentPos = 0;
_stream = new MemoryStream();
StreamWriter writer = new StreamWriter(_stream);
using (SqlConnection cnn = new SqlConnection(_cnnString))
{
cnn.Open();
SqlCommand cmd = new SqlCommand(_sqlString, cnn);
SqlDataReader reader = cmd.ExecuteReader();
int fieldCount = reader.FieldCount;
int rowNum = 0;
UnicodeEncoding encode = new UnicodeEncoding();
List<string> fields = new List<string>();
for (int i = 0; i < fieldCount; i++)
{
fields.Add(reader.GetFieldType(i).Name);
}
while (reader.Read())
{
LiteRowInfo[] rowData = new LiteRowInfo[fieldCount];
for (int i = 0; i < fieldCount; i++)
{
LiteRowInfo info;
if (reader[i] != DBNull.Value)
{
byte[] b;
switch (fields[i])
{
case "Int32":
b = BitConverter.GetBytes(reader.GetInt32(i));
break;
case "Int64":
b = BitConverter.GetBytes(reader.GetInt64(i));
break;
case "DateTime":
DateTime dt = reader.GetDateTime(i);
b = BitConverter.GetBytes(dt.ToBinary());
break;
case "Double":
b = BitConverter.GetBytes(reader.GetDouble(i));
break;
case "Boolean":
b = BitConverter.GetBytes(reader.GetBoolean(i));
break;
case "Decimal":
b = BitConverter.GetBytes((float)reader.GetDecimal(i));
break;
default:
b = encode.GetBytes(reader.GetString(i));
break;
}
int len = b.Length;
info.Position = currentPos += len;
info.Length = len;
info.Field = i;
info.Row = rowNum;
currentPos += len;
_stream.Write(b, 0, len);
}
else
{
info.Position = currentPos;
info.Length = 0;
info.Field = i;
info.Row = rowNum;
}
rowData[i] = info;
}
rowNum++;
pos.Add(rowData);
}
}
}
答案 0 :(得分:8)
鉴于阵列本身是一种参考类型,我非常怀疑你实际上是在看到你认为你所看到的内容。
我怀疑差异不在于为列表添加数组引用 - 我怀疑它首先是创建数组。每个数组元素将占用比引用更多的空间,因此您必须分配更多内存。这可能意味着你也触发了垃圾收集。
要对 List<T>.Add
进行基准测试,我建议您多次重复添加对相同数组的引用。
顺便说一句,将数组作为列表元素类型对我来说感觉有点像嗅觉。有时这是有效的,但我个人会考虑它是否实际上可以封装在另一种类型中。
编辑:你说你发布了所有相关的代码,但真的不是List<T>.Add
的基准代码 - 它包含一件事的数据库访问权限,这几乎可以肯定方式比任何内存中操作更长的时间!
答案 1 :(得分:0)
由于通用列表处理没有装箱的值类型,代码中可能会发生装箱 与<{1}}无关。除非共享代码,否则无法帮助。