os.File.Readdir
kullanarak çok sayıda dosya içeren bir üst dizinden tüm alt dizinleri bulan bir program yazıyorum, ancak sistem çağrısı sayısının tüm dosyalarda lstat()
sürümünü kullanabildiğini görmek için bir strace
çalıştırıyor Üst dizinde/dizinleri bulunur. (Aşağıdaki parçacığı olmadan) program üzerindegolang os * File.Readdir. Optimize edilebilir mi?
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:
Git kodunu (şimdilik /usr/bin
dizin olan bu test ediyorum)
% 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
Ben C'ler readdir()
ile aynı test Bu davranışı görmeden.
C kodu: program üzerinde
#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
Ben POSIX.1'e tarafından görevlendirilmiş olan dirent yapısında sadece alanlar d_name ve d_ino farkındayım ama Bunu belirli bir dosya sistemi için yazıyorum.
bir lstat
kullanabilir ve tüm dosya ve dizinleri bir listesini verir, ancak döndürülen dize bir dosya ya da dizin tekrar lstat
yapmak eninde sonunda olacak olmadığını görmek için etmeyen, *File.Readdirnames()
çalıştı.
- un-ille tüm dosyalar üzerinde
lstat()
önlemek için bir şekilde yeniden yazmak go programı mümkün olup olmadığını merak ediyorum. C programı aşağıdaki syscalls kullandığını görebiliyordum.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 entries */, 32768) = 32752
- Bu, endişelenmemesi gereken, erken bir optimizasyon gibi bir şey midir? Bu soruyu sordum çünkü izlenen dizindeki dosyaların sayısı çok sayıda küçük arşivlenmiş dosyaya sahip olacak ve systemcalls'daki fark, diske vuracak olan
C
veGO
sürümlerinin neredeyse iki katıdır.
[Bu paket] (https://godoc.org/github.com/EricLagergren/go-gnulib/dirent) görünüyor: Aşağıda Go yazılmış C örneğidir. –
Teşekkür ederiz @TimCooper. Eğer bir cevap olarak koyabilirsen, kabul edeceğim. – nohup