golang os * File.Readdir在所有文件上使用lstat.可以优化吗?
我正在编写一个程序,从父目录中查找所有子目录,其中包含使用os.File.Readdir的大量文件,但是运行strace来查看系统调用的计数表明go版本使用的是lstat()在父目录中存在的所有文件/目录上. (我现在用/usr/bin目录测试它)
去代码: package main import ( "fmt" "os" ) func main() { x,err := os.Open("/usr/bin") if err != nil { panic(err) } y,err := x.Readdir(0) if err != nil { panic(err) } for _,i := range y { fmt.Println(i) } } 程序上的Strace(没有跟随线程): % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 93.62 0.004110 2 2466 write 3.46 0.000152 7 22 getdents64 2.92 0.000128 0 2466 lstat // this increases with increase in no. of files. 0.00 0.000000 0 11 mmap 0.00 0.000000 0 1 munmap 0.00 0.000000 0 114 rt_sigaction 0.00 0.000000 0 8 rt_sigprocmask 0.00 0.000000 0 1 sched_yield 0.00 0.000000 0 3 clone 0.00 0.000000 0 1 execve 0.00 0.000000 0 2 sigaltstack 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 1 gettid 0.00 0.000000 0 57 futex 0.00 0.000000 0 1 sched_getaffinity 0.00 0.000000 0 1 openat ------ ----------- ----------- --------- --------- ---------------- 100.00 0.004390 5156 total 我用C的readdir()测试了相同的内容而没有看到这种行为. C代码: #include <stdio.h> #include <dirent.h> int main (void) { DIR* dir_p; struct dirent* dir_ent; dir_p = opendir ("/usr/bin"); if (dir_p != NULL) { // The readdir() function returns a pointer to a dirent structure representing the next // directory entry in the directory stream pointed to by dirp. // It returns NULL on reaching the end of the directory stream or if an error occurred. while ((dir_ent = readdir (dir_p)) != NULL) { // printf("%s",dir_ent->d_name); // printf("%d",dir_ent->d_type); if (dir_ent->d_type == DT_DIR) { printf("%s is a directory",dir_ent->d_name); } else { printf("%s is not a directory",dir_ent->d_name); } printf("n"); } (void) closedir(dir_p); } else perror ("Couldn't open the directory"); return 0; } Strace对该计划: % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000128 0 2468 write 0.00 0.000000 0 1 read 0.00 0.000000 0 3 open 0.00 0.000000 0 3 close 0.00 0.000000 0 4 fstat 0.00 0.000000 0 8 mmap 0.00 0.000000 0 3 mprotect 0.00 0.000000 0 1 munmap 0.00 0.000000 0 3 brk 0.00 0.000000 0 3 3 access 0.00 0.000000 0 1 execve 0.00 0.000000 0 4 getdents 0.00 0.000000 0 1 arch_prctl ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000128 2503 3 total 我知道POSIX.1强制要求的dirent结构中的唯一字段是d_name和d_ino,但我是为特定的文件系统编写的. 尝试* File.Readdirnames(),它不使用lstat并提供所有文件和目录的列表,但是要查看返回的字符串是文件还是目录,最终会再次执行lstat. >我想知道是否有可能重新编写go程序,以避免所有文件上的lstat()不一定.我可以看到C程序正在使用以下系统调用. open(“/usr/bin”,O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)= 3
包
dirent 看起来像是完成了你想要的东西.下面是您在Go中编写的C示例:
package main import ( "bytes" "fmt" "io" "github.com/EricLagergren/go-gnulib/dirent" "golang.org/x/sys/unix" ) func int8ToString(s []int8) string { var buff bytes.Buffer for _,chr := range s { if chr == 0x00 { break } buff.WriteByte(byte(chr)) } return buff.String() } func main() { stream,err := dirent.Open("/usr/bin") if err != nil { panic(err) } defer stream.Close() for { entry,err := stream.Read() if err != nil { if err == io.EOF { break } panic(err) } name := int8ToString(entry.Name[:]) if entry.Type == unix.DT_DIR { fmt.Printf("%s is a directoryn",name) } else { fmt.Printf("%s is not a directoryn",name) } } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |