我正在编写一个程序,使用
Go代码:
程序上的Strace(不跟随线程):
我使用了C语言的
C代码:
程序上的Strace:
我知道在POSIX.1中强制规定的dirent结构中仅有d_name和d_ino两个字段,但我正在为特定的文件系统编写此代码。
尝试使用*File.Readdirnames()函数,该函数不使用lstat并提供所有文件和目录的列表,但是要查看返回字符串是文件还是目录最终又需要再次使用lstat。
我想知道是否有可能以一种避免不必要地对所有文件进行lstat()的方式重新编写go程序。我发现C程序正在使用以下系统调用open(“/usr/bin”,O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)= 3 fstat(3,{st_mode = S_IFDIR | 0755,st_size = 69632,...})= 0 brk(NULL)= 0x1098000 brk(0x10c1000)= 0x10c1000 getdents(3,/ * 986条目 * /,32768)= 32752
这是否像是过早优化的问题,不必担心?我提出这个问题是因为被监视的目录中的文件数量将具有大量小归档文件,并且系统调用之间的差异几乎是C版本和GO版本之间的两倍,这将影响磁盘。
os.File.Readdir
查找所有子目录,这些子目录包含大量文件的父目录。但是运行strace
以查看系统调用计数时,发现Go版本在父目录中的所有文件/目录上使用了lstat()
。(我现在正在使用/usr/bin
目录进行测试)Go代码:
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。
我想知道是否有可能以一种避免不必要地对所有文件进行lstat()的方式重新编写go程序。我发现C程序正在使用以下系统调用open(“/usr/bin”,O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)= 3 fstat(3,{st_mode = S_IFDIR | 0755,st_size = 69632,...})= 0 brk(NULL)= 0x1098000 brk(0x10c1000)= 0x10c1000 getdents(3,/ * 986条目 * /,32768)= 32752
这是否像是过早优化的问题,不必担心?我提出这个问题是因为被监视的目录中的文件数量将具有大量小归档文件,并且系统调用之间的差异几乎是C版本和GO版本之间的两倍,这将影响磁盘。