C# 遍历IEnumerable<;字符串>;导致严重的性能问题
当我尝试遍历IEnumerable类型时,我对for循环的性能所发生的事情知之甚少 以下是导致严重性能问题的代码C# 遍历IEnumerable<;字符串>;导致严重的性能问题,c#,performance,C#,Performance,当我尝试遍历IEnumerable类型时,我对for循环的性能所发生的事情知之甚少 以下是导致严重性能问题的代码 foreach (IEdge ed in edcol) { IEnumerable<string> row = from r in dtRow.AsEnumerable() where (((r.Field<string>("F1") == ed.Vertex1.Name) &&
foreach (IEdge ed in edcol)
{
IEnumerable<string> row =
from r in dtRow.AsEnumerable()
where (((r.Field<string>("F1") == ed.Vertex1.Name) &&
(r.Field<string>("F2") == ed.Vertex2.Name))
|| ((r.Field<string>("F1") == ed.Vertex2.Name) &&
(r.Field<string>("F2") == ed.Vertex1.Name)))
select r.Field<string>("EdgeId");
int co = row.Count();
//foreach (string s in row)
//{
//}
x++;
}
从代码中
row.Count()在所有循环中的最大值为10
如果我取消注释
//foreach (string s in row)
//{
//}
完成代码的执行大约需要10分钟
IEnumerable类型是否存在如此严重的性能问题 目前您有O(N*M)性能,如果N和M都很大,这可能是个问题。我倾向于预先计算一些DataTable
info。例如,我们可以尝试:
var lookup = dtRows.AsEnumerable().ToLookup(
row => string.Compare(row.Field<string>("F1"),row.Field<string>("F2"))<0
? Tuple.Create(row.Field<string>("F1"), row.Field<string>("F2"))
: Tuple.Create(row.Field<string>("F2"), row.Field<string>("F1")),
row => row.Field<string>("EdgeId"));
var lookup=dtRows.AsEnumerable().ToLookup(
row=>string.Compare(row.Field(“F1”)、row.Field(“F2”))和row.Field(“EdgeId”);
然后我们可以迭代:
foreach(IEdge ed in edCol)
{
var name1 = string.Compare(ed.Vertex1.Name,ed.Vertex2.Name) < 0
? ed.Vertex1.Name : ed.Vertex2.Name;
var name2 = string.Compare(ed.Vertex1.Name,ed.Vertex2.Name) < 0
? ed.Vertex2.Name : ed.Vertex1.Name;
var matches = lookup[Tuple.Create(name1,name2)];
// ...
}
foreach(在edCol中编辑边缘)
{
var name1=string.Compare(ed.Vertex1.Name,ed.Vertex2.Name)<0
?ed.Vertex1.Name:ed.Vertex2.Name;
var name2=string.Compare(ed.Vertex1.Name,ed.Vertex2.Name)<0
?ed.Vertex2.Name:ed.Vertex1.Name;
var matches=lookup[Tuple.Create(name1,name2)];
// ...
}
(注意,为了方便起见,我在这里强制使用了按字母顺序升序的配对)这个答案是针对一个隐含的问题:“我如何使它更快”?如果这不是你想要的,我道歉,但是 您可以按名称对行进行一次分组。(我没有像Marc那样进行排序-我只是在查询时查找了两次:)
如果没有
计数
将不会对查询进行评估。性能问题可能是dtRow.AsEnumerable()
@mipe34不太可能;这实际上没什么作用;LINQ中的大多数东西都使用延迟执行如果dtRow.AsEnumerable()是性能问题,那么为什么从代码中删除row.count()行时代码会在几秒钟内运行?@Jon那里没有与数据库对话的代码。从显示的代码中,dtRow
看起来是一个DataTable
。DataTable
不会因为您查看它而加载自身:要么它有数据,要么它没有数据。有时我担心我们处理事情的方式有多相似。非常小的区别-为了避免Concat
,我强制使用升序元组并使用元素投影。@marcGravel:是的。。。我不知道哪一个会更快,但我怀疑这会有多大区别。这将在3秒钟内执行datatable中约500000条记录的代码!!!谢谢lot@RajeevKumar:你明白为什么吗?@RajeevKumar:你明白为什么原始代码很慢。。。为什么如果你调用Count()
调用(以及内部foreach
循环),它会很快呢?@JonSkeet-er,是的,可能吧
foreach(IEdge ed in edCol)
{
var name1 = string.Compare(ed.Vertex1.Name,ed.Vertex2.Name) < 0
? ed.Vertex1.Name : ed.Vertex2.Name;
var name2 = string.Compare(ed.Vertex1.Name,ed.Vertex2.Name) < 0
? ed.Vertex2.Name : ed.Vertex1.Name;
var matches = lookup[Tuple.Create(name1,name2)];
// ...
}
var lookup = dtRow.AsEnumerable()
.ToLookup(r => new { F1 = r.Field<string>("F1"),
F2 = r.Field<string>("F2") });
foreach (IEdge ed in edcol)
{
// Need to check both ways round...
var first = new { F1 = ed.Vertex1.Name, F2 = ed.Vertex2.Name };
var second = new { F1 = ed.Vertex2.Name, F2 = ed.Vertex1.Name };
var firstResult = lookup[first];
var secondResult = lookup[second];
// Due to the way Lookup works, this is quick - much quicker than
// calling query.Count()
var count = firstResult.Count() + secondResult.Count();
var query = firstResult.Concat(secondResult);
foreach (var row in query)
{
...
}
}