我需要一些帮助。现在我已经完成了一个文件搜索,它将搜索我的整个硬盘并且它可以工作。以下是实现它的两种方法。
public void SearchFileRecursiveNonMultithreaded()
{
//Search files multiple drive
string[] drives = Environment.GetLogicalDrives();
foreach (string drive in drives)
{
if (GetDriveType(drive).ToString().CompareTo("DRIVE_FIXED") == 0)
{
DriveInfo driveInfo = new DriveInfo(drive);
if (driveInfo.IsReady)
{
System.IO.DirectoryInfo rootDirectory = driveInfo.RootDirectory;
RecursiveFileSearch(rootDirectory);
}
}
}
MessageBox.Show(files.Count.ToString());
}
public void RecursiveFileSearch(DirectoryInfo root)
{
DirectoryInfo[] subDirectory;
try
{
//private List<FileInfo> files = new List<FileInfo>() is declared above
files.AddRange(root.GetFiles(searchString.Text, SearchOption.TopDirectoryOnly));
}
catch (Exception)
{
}
try
{
// Now find all the subdirectories under this directory.
subDirectory = root.GetDirectories();
foreach (System.IO.DirectoryInfo dirInfo in subDirectory)
{
// Resursive call will be performed for each subdirectory.
RecursiveFileSearch(dirInfo);
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
现在我正在尝试实施并行搜索以加快搜索速度。我尝试了几个程序来实现这一点。试图使用backgroundworker以及线程,但有问题,调试很难知道什么是错的?有人能让我知道实现并行搜索的方法。这个步骤我会自己去弄清楚。所提供的任何帮助都会得到很大的帮助。
答案 0 :(得分:5)
首先,正如其他人所指出的那样,当您只搜索一个驱动器时,使用多个线程不太可能加快速度。您的绝大部分时间都花在等待磁盘头移动到需要的位置,并且它一次只能在一个地方。在这里使用多个线程是浪费精力,并且很可能实际上使你的程序变慢。
其次,只需调用Directory.EnumerateFiles即可简化代码。如果您想同时搜索多个驱动器,只需启动多个BackgroundWorker
实例,每个实例使用EnumerateFiles
搜索不同的驱动器。
但请注意,EnumerateFiles
如果跨目录权限问题运行会引发异常(代码也会如此),这在搜索整个驱动器时并不常见。如果这是一个问题(可能会是),那么你必须编写自己的目录搜索器。其中一个就是this question的答案。
答案 1 :(得分:1)
您的外圈foreach (string drive in drives)
可以从更改为Parallel.ForEach()
获得。
你的内循环(RecursiveFileSearch()
)应该不并行,你只会失去性能。但是从Fx4中,您可以将GetFiles()
替换为EnumerateFiles()
,以便在非常大的文件夹上获得更好的结果。
这解决了大部分踏板安全问题,外部循环应该为每个要填充的驱动器提供一个列表(非异步)。然后,在ForEach()之后合并这些列表。
确切的答案更加困难:并行搜索逻辑磁盘无济于事,增益将来自独立的“车轴”。但是在一个大的RAID卷上,搜索文件可能会受益于一些额外的线程。
答案 2 :(得分:1)
虽然同时搜索逻辑驱动器可能有助于或损害性能,但以下是管理线程的方法:
using System.Threading;
...
string[] drives = Environment.GetLogicalDrives();
List<Thread> threads = new List<Thread>();
foreach (string drive in drives)
{
if (GetDriveType(drive).ToString().CompareTo("DRIVE_FIXED") == 0)
{
DriveInfo driveInfo = new DriveInfo(drive);
if (driveInfo.IsReady)
{
System.IO.DirectoryInfo rootDirectory = driveInfo.RootDirectory;
var thread = new Thread((dir) => RecursiveFileSearch((DirectoryInfo)dir));
threads.Add(thread);
thread.Start(rootDirectory);
}
}
}
foreach(var t in threads) t.Join();
MessageBox.Show(files.Count.ToString());
不要忘记锁定RecursiveFileSearch
使用的任何共享集合。您应该尝试避免此类访问,因为它会产生争用。
答案 3 :(得分:0)
使其成为多线程的一种解决方案是将对RecursiveFileSearch的每个调用转储到ThreadPool.QueueUserWorkItem中,以使其在多个线程上运行。
现在,请注意这种方法,原因如下:
1)正如Dypple所说,访问驱动器是单线程的,所以这实际上可能会影响性能
2)列表不是线程安全的,因此在添加到列表之前需要对其进行锁定/同步。这也可能会影响性能。考虑使用System.Collections.Concurrent.ConcurrentBag(在.NET 4.0中)让它为您控制同步,因为您只是在做补充。
3)如果您的MaxIntFiles大于MaxIntFiles,则将您遇到的每个文件添加到列表中都可能导致溢出。
4)此文件集可能会变得庞大,并可能导致内存不足异常。