对不起,如果标题不是很合适,我实际上有多个问题,我无法将它们分开。
我写了一个在macOS上运行的命令行“find”程序的简化版本,它只是在指定路径中查找文件名的每个示例,并打印相应的文件路径(如果有的话)和最后修改的日期。这是一个单线程程序。我使用了readdir和lstat来获取必要的文件信息。
然后我比较了我的程序的性能,让我们称之为“myfind”(打印文件路径和最后修改时间),以“find”(与“find path -name filename”一起使用,只打印结果文件路径)。“myfind”用了100万个40秒,而“find”只用了40秒。在连续的尝试中,两次都是一致的。
对结果不满意,我做了一些“优化”,但没有做任何事情(比如删除递归,使用一个简单的堆栈来保存一些变量)。
这是我写的代码,删除了错误检查(执行或不执行错误检查不会改变执行时间):
struct recstruct{
DIR *st_dir;
char pathname[512];
};
//usage: ./execname path filename
int main(int argc, char *argv[]){
chdir(argv[1]);
myfind(argv[2]);
return 0;
}
int myfind(char *name){
DIR *curr_dir = opendir(".");
int stk_i = 0;
struct recstruct stk[128];
struct dirent *next_entry;
struct stat info;
char *entry_name;
char path[512];
errno = 0;
//ignores "." and ".."
readdir(curr_dir);
readdir(curr_dir);
//gets next directory entry until it has fully explored the path
while((next_entry = readdir(curr_dir)) != NULL || stk_i != 0){
//goes back to previous directory if there is any and it's done with the current one
if(next_entry == NULL){
closedir(curr_dir);
stk_i--;
chdir(stk[stk_i].pathname);
curr_dir = stk[stk_i].st_dir;
continue;
}
//gets next directory entry and checks if its name is the one we are looking for
entry_name = next_entry->d_name;
lstat(entry_name, &info);
if(strncmp(name, entry_name, 127) == 0){
realpath(entry_name, path);
printf("path:%s\nlast modified:%s", path, ctime(&(info.st_mtime)));
}
//if next_entry is a dir, save current environment and explore the new dir
if(S_ISDIR(info.st_mode)){
getcwd(stk[stk_i].pathname, 512);
stk[stk_i].st_dir = curr_dir;
stk_i++;
chdir(entry_name);
curr_dir = opendir(".");
readdir(curr_dir);
readdir(curr_dir);
}
}
closedir(curr_dir);
return 0;
}
然后,通过删除所有lstat调用,从“myfind”中删除了打印最后修改日期的部分。执行时间降到了30秒,在连续调用(来自终端的程序调用,而不是函数调用)时降到了大约3-6秒。即使在关闭和重新开放航站楼后,改善仍然存在)。
这种行为还改善了在目录树中查找文件关闭的连续调用的执行时间,这似乎是这种类型的程序的可能使用场景,所以我希望能够更多地理解它。
所以我想问的是
1.这种对连续调用的执行时间的改进是如何确切地起作用的?为什么在使用lstat时,“find”和“myfind”中都没有它?
1.有没有其他的东西我可以改变我的代码,使它更优化,同时使它也打印最后修改日期?我也可以让它依赖于平台。
我在SSD上操作,每次执行只查找1个文件名
1条答案
按热度按时间xwbd5t1u1#
下面是@EricPostpischil建议的
fts_
实现。它假设用户提供了一个目录,如果你想验证在循环之前执行第一个fts_read()
并检查fts_info
。它还假设文件名是一个基本名(不包含任何斜杠)。你也可以检查一下。查看
fts_open()
的选项,确保这是您想要的行为。它只是检查文件名是否与常规文件匹配;
find -name
也将匹配目录名称。很容易在for
-循环之前解决这个问题。下面是一些运行示例(使用热文件缓存进行比较):
我看到~ 3. 9到~ 7. 6真实的运行在我的系统上,所以应该是可比的发现。