如何提高此 MFC 代码的性能?
-
12-10-2019 - |
题
我进行文件搜索,并且有目录的例外列表,问题是下面的代码递归地迭代硬盘驱动器上的所有文件。它有效,但速度很慢。因此,我需要帮助来优化其性能。提前致谢。
CFileFind finder;
// build a string with wildcards
CString strWildcard(directory);
strWildcard += _T("\\*.*");
// start working for files
BOOL bWorking = finder.FindFile(strWildcard);
while (bWorking)
{
bWorking = finder.FindNextFile();
if (finder.IsDots())
continue;
// if it's a directory, recursively search it
if (finder.IsDirectory())
{
CString str = finder.GetFilePath();
if(NULL == m_searchExceptions.Find(str)){
_recursiveSearch(str);
}
else{
continue;
}
}
//basic comparison, can be replaced by strategy pattern if complicated comparsion required (e.g. REGEX)
if(0 == finder.GetFileName().CompareNoCase(m_searchPattern)){
if(m_currentSearchResults.Find(finder.GetFilePath()) == NULL){
m_currentSearchResults.AddHead(finder.GetFilePath());
}
}
}
解决方案
我认为您将无法在这里优化性能。您将在里面花费80%以上的时间 FindFirstFile
和 FindNextFile
在这里(Windows API调用)无论您在最终的优化方面做什么。
我已经问了一个类似的问题 并且尚未得到答案。
其他提示
看起来像你的 m_currentSearchResults
是一个列表,每次找到文件名时都会查找它是否已在列表中。如果您有大量找到的文件(例如数百个),这可能会成为瓶颈,因为它已经 O(N^2)
复杂。如果是这种情况,请考虑使用 CMap
相反,因为它给你 O(log N)
搜索(集合比地图更合适,但是 MFC 中没有这个,但您也可以使用标准库的 std::set
反而)。
有多慢?你介绍了吗?如果您递归地在硬盘上搜索文件,那么您很可能是我/o绑定的,没有什么可以做的,而无需获得更快的存储硬件(例如固态)。
您正在对文件进行一般搜索。有一百万个产品可以很好地做到这一点,并且它们都将索引作为优化。这里的薄弱环节当然是您的磁盘,而不是您的代码。与在磁盘上列举1,000,000个文件所需的时间相比,比较1,000,000个字符串将不需要时间。
此处的性能有两个基本问题:硬盘驱动访问和目录遍历。你们俩 可能 能够优化。
硬盘优化
休息时的硬盘往往会保持静止。旋转的圆柱体喜欢继续旋转。因此说,硬盘驱动器中的瓶颈正在开始,寻找时间和阅读时间。减少访问的数量并增加每个读取的数据数量将提高您的性能。
内存访问比硬盘驱动器访问更快。因此,将大量数据拖到内存中,然后搜索内存。
优化目录搜索。
想象一下,如果您愿意,一棵“页面”树。树上的每个节点都是零或更多目录或文件的目录。不幸的是,在大多数操作系统中,此数据结构并未优化用于有效搜索。
理想的情况是将所有相关目录拖到内存中,然后将其搜索(内存)。一旦已知文件的位置,对文件的随机访问相对较快。问题是仅阅读相关目录来减少搜索时间;即减少无关目录读取的数量。
在硬盘驱动器上执行文件搜索的大多数应用程序读取驱动器并创建自己的优化数据结构。对于带有数量的文件或少量文件搜索案例的巨大硬盘驱动器,这可能不是最佳的。
如果可以的话,请告诉操作系统以使尽可能多的目录保持在内存中。
提高性能:减少其他应用程序。
对于某些应用程序,感知的性能时间取决于同时运行的其他应用程序。同时运行编译器和Internet搜索将减慢大多数其他应用程序。因此,请尝试消除与您的同时运行中不需要的其他应用程序。此外,投资限制申请的优先级。
+1首先要确定它。另外,这似乎是一个问题,也可以使用 任务并行库 - 在看到每个目录时启动任务,并在CPU上使用所有这些内核 -