C# 处理IEnumerable c时的性能问题#
我目前正在编写一个个人项目,用于潜入二叉树并搜索新的或更改的文件。我想保存所有文件,我的搜索已发现与路径和md5校验和到一个csv文件的比较后记。这些文件作为我自己的类iFile的对象加载到IEnumerable变量中。 但是csv文件的编写只需要大约5分钟就可以处理15000个文件。(处理IEnumerable to List需要1分钟6秒)有没有办法加快我的代码速度 这是我的递归搜索:C# 处理IEnumerable c时的性能问题#,c#,csv,optimization,ienumerable,issue-tracking,C#,Csv,Optimization,Ienumerable,Issue Tracking,我目前正在编写一个个人项目,用于潜入二叉树并搜索新的或更改的文件。我想保存所有文件,我的搜索已发现与路径和md5校验和到一个csv文件的比较后记。这些文件作为我自己的类iFile的对象加载到IEnumerable变量中。 但是csv文件的编写只需要大约5分钟就可以处理15000个文件。(处理IEnumerable to List需要1分钟6秒)有没有办法加快我的代码速度 这是我的递归搜索: public static IEnumerable<iFile> GetAllFiles(st
public static IEnumerable<iFile> GetAllFiles(string root, bool ignoreUnauthorizedAccess = true)
{
Stack<string> stack = new Stack<string>();
stack.Push(root);
while (stack.Count > 0)
{
string curDir = stack.Pop();
string[] files = null;
try
{
files = Directory.GetFiles(curDir);
}
catch (UnauthorizedAccessException)
{
if (!ignoreUnauthorizedAccess) throw;
}
catch (IOException)
{
if (!ignoreUnauthorizedAccess) throw;
}
if (files != null)
foreach (string file in files)
{
iFile f = new iFile(new FileInfo(file));
yield return f;
}
string[] dirs = null;
try
{
dirs = Directory.GetDirectories(curDir);
}
catch (UnauthorizedAccessException)
{
if (!ignoreUnauthorizedAccess) throw;
}
catch (IOException)
{
if (!ignoreUnauthorizedAccess) throw;
}
if (dirs != null)
foreach (string dir in dirs)
stack.Push(dir);
}
}
公共静态IEnumerable GetAllFiles(字符串根,bool ignoreUnauthorizedAccess=true)
{
堆栈=新堆栈();
栈.推(根);
而(stack.Count>0)
{
字符串curDir=stack.Pop();
string[]files=null;
尝试
{
files=Directory.GetFiles(curDir);
}
捕获(未经授权的访问例外)
{
如果(!ignoreUnauthorizedAccess)抛出;
}
捕获(IOException)
{
如果(!ignoreUnauthorizedAccess)抛出;
}
如果(文件!=null)
foreach(文件中的字符串文件)
{
iFile f=新iFile(新文件信息(文件));
收益率f;
}
字符串[]dirs=null;
尝试
{
dirs=Directory.GetDirectories(curDir);
}
捕获(未经授权的访问例外)
{
如果(!ignoreUnauthorizedAccess)抛出;
}
捕获(IOException)
{
如果(!ignoreUnauthorizedAccess)抛出;
}
如果(dirs!=null)
foreach(dirs中的字符串dir)
堆栈推送(dir);
}
}
这是我的写作功能:
private static void writeToSystem<iFile>(this IEnumerable<iFile> files, string path = "c:\")
{
using (System.IO.StreamWriter f = new System.IO.StreamWriter(path))
{
foreach (var i in files)
{
f.WriteLine(i.getPath() + ";" + i.getHash());
}
}
}
private static void writeSystem(此IEnumerable files,string path=“c:\”)
{
使用(System.IO.StreamWriter f=new System.IO.StreamWriter(路径))
{
foreach(文件中的var i)
{
f、 WriteLine(i.getPath()+“;+i.getHash());
}
}
}
以及iFile类中的getHash函数:
using (var md5 = new MD5CryptoServiceProvider())
{
if(File.Exists(@filename) && fInfo.Length < 100000 ){
try
{
byte[] data = md5.ComputeHash(Encoding.Default.GetBytes(filename),0,2000);
return BitConverter.ToString(data);
}
catch (Exception)
{
Program.logger.log("Fehler beim MD5 erstellen!", Program.logger.LOG_ERROR);
return "";
}
} else {
return "";
}
}
使用(var md5=new MD5CryptoServiceProvider())
{
if(File.Exists(@filename)&&fInfo.Length<100000){
尝试
{
byte[]data=md5.ComputeHash(Encoding.Default.GetBytes(filename),02000);
返回BitConverter.ToString(数据);
}
捕获(例外)
{
Program.logger.log(“Fehler beim MD5 erstellen!”,Program.logger.log\u错误);
返回“”;
}
}否则{
返回“”;
}
}
我认为您的getPath()和getHash()非常耗时
i、 getPath()+“;”+i.getHash()
为了并行化您的工作负载,您必须重新构造代码 以下方法将顺序目录遍历与处理每个目录中的文件的并行任务结合起来。因此,不同的目录将被并行检查,但一个目录中的所有文件将在此任务中再次按顺序处理。这可能适用于具有子目录的结构,其中每个目录包含的文件不太多。如果一个目录包含大量文件,或者如果有许多目录每个目录都包含少量文件,则可能需要不同的并行化
public static async Task<IEnumerable<string>> ProcessAllFiles(string root, Func<iFile, string> fileToLineConverter, bool ignoreUnauthorizedAccess = true)
{
Stack<string> stack = new Stack<string>();
List<Task<IEnumerable<string>>> resultTasks = new List<Task<IEnumerable<string>>>();
stack.Push(root);
while (stack.Count > 0)
{
string curDir = stack.Pop();
resultTasks.Add(Task.Run(() => ProcessFilesInDirectory(curDir, fileToLineConverter, ignoreUnauthorizedAccess)));
string[] dirs = null;
try
{
dirs = Directory.GetDirectories(curDir);
}
catch (UnauthorizedAccessException)
{
if (!ignoreUnauthorizedAccess) throw;
}
catch (IOException)
{
if (!ignoreUnauthorizedAccess) throw;
}
if (dirs != null)
foreach (string dir in dirs)
stack.Push(dir);
}
var results = await Task.WhenAll(resultTasks);
return results.SelectMany(x => x);
}
private static IEnumerable<string> ProcessFilesInDirectory(string curDir, Func<iFile, string> fileToLineConverter, bool ignoreUnauthorizedAccess)
{
FileInfo[] files = null;
try
{
var dir = new DirectoryInfo(curDir);
files = dir.GetFiles();
}
catch (UnauthorizedAccessException)
{
if (!ignoreUnauthorizedAccess) throw;
}
if (files != null)
return files.Select(x => fileToLineConverter(new iFile(x))).ToList();
return Enumerable.Empty<string>();
}
async Task ExecuteFull(string path)
{
var lines = await ProcessAllFiles(
@"C:\",
x => x.getPath() + ";" + x.getHash(),
false);
using (System.IO.StreamWriter f = new System.IO.StreamWriter(path))
{
foreach (var i in lines)
{
f.WriteLine(lines);
}
}
}
public static async Task ProcessAllFiles(字符串根,Func fileToLineConverter,bool ignoreUnauthorizedAccess=true)
{
堆栈=新堆栈();
列表结果任务=新列表();
栈.推(根);
而(stack.Count>0)
{
字符串curDir=stack.Pop();
结果tasks.Add(Task.Run(()=>ProcessFilesInDirectory(curDir、fileToLineConverter、ignoreUnauthorizedAccess));
字符串[]dirs=null;
尝试
{
dirs=Directory.GetDirectories(curDir);
}
捕获(未经授权的访问例外)
{
如果(!ignoreUnauthorizedAccess)抛出;
}
捕获(IOException)
{
如果(!ignoreUnauthorizedAccess)抛出;
}
如果(dirs!=null)
foreach(dirs中的字符串dir)
堆栈推送(dir);
}
var结果=等待任务.WhenAll(结果任务);
返回结果。选择many(x=>x);
}
私有静态IEnumerable ProcessFileIndirectory(字符串curDir、Func fileToLineConverter、bool ignoreUnauthorizedAccess)
{
FileInfo[]files=null;
尝试
{
var dir=新目录信息(curDir);
files=dir.GetFiles();
}
捕获(未经授权的访问例外)
{
如果(!ignoreUnauthorizedAccess)抛出;
}
如果(文件!=null)
返回文件。选择(x=>fileToLineConverter(新iFile(x)).ToList();
返回可枚举的.Empty();
}
异步任务执行文件(字符串路径)
{
var lines=wait ProcessAllFiles(
@“C:\”,
x=>x.getPath()+“;”+x.getHash(),
假);
使用(System.IO.StreamWriter f=new System.IO.StreamWriter(路径))
{
foreach(行中的var i)
{
f、 写线(行);
}
}
}
有没有办法加快我的代码速度
是的,只要将磁盘换成更现代的SSD,并使用多线程处理你的文件和任务,这样GetAllFiles
看起来就快了,因为的收益率
。在返回IEnumerable
之前,它实际上并没有执行整个搜索。搜索文件系统的代码在枚举时以增量方式运行