C# .net大,用于循环减速
我有一个大的for循环(最多30k次迭代),它似乎一直在减速:C# .net大,用于循环减速,c#,.net,asynchronous,C#,.net,Asynchronous,我有一个大的for循环(最多30k次迭代),它似乎一直在减速: 前一千次迭代需要1.34秒 在12k次迭代之后,接下来的1000次需要5.31秒 在23k次迭代之后,接下来的1000次需要6.65秒 最后一千次迭代需要7.43秒 为了获得一点性能,我从foreach循环切换到for循环,并尝试了发布配置,但我找不到其他适用于我的配置。循环采用异步方法 为什么循环会变慢?可以避免吗 for(int iter = 0; iter < LargeList1.Count; iter++) {
- 前一千次迭代需要1.34秒
- 在12k次迭代之后,接下来的1000次需要5.31秒
- 在23k次迭代之后,接下来的1000次需要6.65秒
- 最后一千次迭代需要7.43秒
foreach
循环切换到for
循环,并尝试了发布配置,但我找不到其他适用于我的配置。循环采用异步方法
为什么循环会变慢?可以避免吗
for(int iter = 0; iter < LargeList1.Count; iter++)
{
var cl_from = LargeList1[iter];
if(LargeList2.Any(cl => cl.str.Contains(cl_from.str)))
{
DateTime dt1 = //last write time of a file
DateTime dt2 = //last write time of a different file
if(DateTime.Compare(dt1, dt2) > 0)
{
try
{
CopyFile(//Kernel32 CopyFile a file overwrite);
globals.fileX++;
}
catch(Exception filexx)
{
//error handler
}
}
else
{
globals.fileS++;
}
}
else
{
Directory.CreateDirectory(//create a directory, no check if it already exists);
try
{
CopyFile(//Kernel32 CopyFile a file do not overwrite);
globals.fileX++;
}
catch(Exception filex)
{
// error handler
}
}
gui.UpdateCount(globals.fileF, globals.fileX, globals.fileS); //updates iteration on textboxes
float p = (float)100.0*((float)globals.fileF + (float)globals.fileX + (float)globals.fileS)/(float)globals.totalCount;
gui.setProgress(p); //updates progressbar
}
for(int-iter=0;itercl.str.Contains(cl_from.str)))
{
DateTime dt1=//文件的上次写入时间
DateTime dt2=//不同文件的上次写入时间
如果(DateTime.Compare(dt1,dt2)>0)
{
尝试
{
CopyFile(//Kernel32 CopyFile a文件覆盖);
globals.fileX++;
}
捕获(异常文件xx)
{
//错误处理程序
}
}
其他的
{
globals.fileS++;
}
}
其他的
{
CreateDirectory(//创建一个目录,不检查它是否已经存在);
尝试
{
CopyFile(//Kernel32 CopyFile a文件不覆盖);
globals.fileX++;
}
捕获(异常文件x)
{
//错误处理程序
}
}
gui.UpdateCount(globals.fileF、globals.fileX、globals.fileS);//更新文本框上的迭代
float p=(float)100.0*((float)globals.fileF+(float)globals.fileX+(float)globals.fileS)/(float)globals.totalCount;
setProgress(p);//更新progressbar
}
编辑:正如许多人建议的那样,使用hashset.Contains(cl_from.str)解决了这个问题。我可以想象这两个项目的性质将是瓶颈
for(int iter = 0; iter < LargeList1.Count; iter++)
{
.....
if(LargeList2.Any(cl => cl.str.Contains(cl_from.str)))
...........
for(int-iter=0;itercl.str.Contains(cl_from.str)))
...........
您正在检查当前字符串中是否包含其他大列表中的任何单词
它可能会随着时间的推移而变慢的几个原因:
cl_from.st
可能越来越大cl\u from.str
和LargeList2
有多大,是否值得为cl\u from.str
中的所有可能值创建一个散列,然后检查是否有查找,甚至可能创建一个包含所有LargeList2字符串的散列集,然后使用该散列集,在cl\u from.str
中迭代每个字符串组合>我敢肯定,冒犯的界线是:
if(LargeList2.Any(cl => cl.str.Contains(cl_from.str)))
由于匿名委托的开销,带有lambda表达式的“Any”扩展方法最终将比正手版本慢,因此您可以尝试扩展如下:
foreach (var cl in LargeList2)
{
if (cl.str.Contains(cl_from.str))
{
// do stuff
break;
}
}
但我认为,在这个迭代过程中,你可能会发现匿名委托和字符串函数的缓慢性。很可能迭代过程必须通过大多数LargeList2才能在迭代过程中找到匹配项,这意味着随着过程的进行,性能会变慢
尝试在启用行级计时的情况下使用ANTS performance profiler,查看运行此进程后是否将此行显示为热点。另一种可能是文件系统给您带来了麻烦。如果单个文件夹中有数千个文件,打开一个文件可能需要很长时间。系统会加载目录并执行此操作查找所请求文件项的顺序搜索 如果您正在获取目录中的文件列表,然后逐个打开它们,则随着您进入该列表,打开文件所需的时间将越来越长。例如,如果您有:
foreach (var filename in Directory.GetFiles(...))
{
// start stopwatch
// open the file
// stop stopwatch
// display time
// close the file
}
你会发现,打开文件的时间会随着你在文件列表中的位置越来越远而增加。当你谈论几百个文件时,这种差异其实并不显著,但当你在一个文件夹中有10000个文件时,这种差异就变得非常明显了
解决方案是将事情分解,这样一个文件夹中就不会有那么多文件。与单个文件夹中的10000个文件不同,一个文件夹中有100个文件,一个文件夹中有100个文件。或者10个文件夹,每个文件夹中有1000个文件。这两者都比一个文件夹中有大量文件的速度快得多。迭代次数n-m取x是什么意思这意味着任何时候都有那么多的迭代,或者第一次/最后一次c迭代需要时间?迭代29k-30k-take 7.43s意味着最后1000次迭代需要7.43秒。我将更新它以澄清您是否考虑过在给定的迭代次数后尝试使用条件断点来评估
for
循环?另外,您不能使用原始断点吗数组而不是列表?它们应该快得多。我的假设是该部分稍后在LargeList2.Any(cl=>cl.str.Contains(cl\u from.str))
上会变慢。如果结果从LargeList2很晚生成,那么这将需要更多的时间。也许您可以以某种方式优化匹配(例如,如果匹配项不重复,则从列表中删除元素,记住索引,使用已匹配项字典等)您的算法实际上是O(n^2)-对于LargeList1
中的每个条目,您必须搜索LargeList2
以查找匹配项。如果