我原本假设access()只是stat()的一个包装器,但是我一直在谷歌上搜索link关于用更便宜的'替换stat调用。访问电话。假设您只对检查文件是否存在感兴趣,访问速度更快吗?文件系统完全不同吗?
答案 0 :(得分:9)
我对此表示怀疑。
在较低的内核层中,access()
和stat()
调用之间没有太大区别,它们都在执行查找操作:它们将文件名映射到中的条目dentry cache 和 inode (它是实际的内核结构,inode
)。查找是缓慢的操作,因为您需要为路径的每个部分执行它,即对于/usr/bin/cat
,您需要查找usr
,bin
然后cat
并且它可能需要从磁盘读取 - 这就是为什么inode和dentries被缓存在内存中。
这些调用之间的主要区别在于stat()
执行inode
结构到stat
结构的转换,而access()
会进行简单的检查,但是时间比较小查找时间。
- faccessat()
和fstatat()
等操作可以实现真正的性能提升,允许open()
目录一次,只需比较:
struct stat s;
stat("/usr/bin/cat", &s); // lookups usr, bin and cat = 3
stat("/usr/bin/less", &s); // lookups usr, bin and less = 3
int fd = open("/usr/bin"); // lookups usr, bin = 2
fstatat(fd, "cat", &s); // lookups cat = 1
fstatat(fd, "less", &s); // lookups less = 1
我写了一个小的python脚本,调用stat()
和access()
:
import os, time, random
files = ['gzexe', 'catchsegv', 'gtroff', 'gencat', 'neqn', 'gzip',
'getent', 'sdiff', 'zcat', 'iconv', 'not_exists', 'ldd',
'unxz', 'zcmp', 'locale', 'xz', 'zdiff', 'localedef', 'xzcat']
access = lambda fn: os.access(fn, os.R_OK)
for i in xrange(1, 80000):
try:
random.choice((access, os.stat))("/usr/bin/" + random.choice(files))
except:
continue
我使用SystemTap跟踪系统以测量在不同操作中花费的时间。 stat()
和access()
系统调用都使用user_path_at_empty()
内核函数来表示查找操作:
stap -ve ' global tm, times, path;
probe lookup = kernel.function("user_path_at_empty")
{ name = "lookup"; pathname = user_string_quoted($name); }
probe lookup.return = kernel.function("user_path_at_empty").return
{ name = "lookup"; }
probe stat = syscall.stat
{ pathname = filename; }
probe stat, syscall.access, lookup
{ if(pid() == target() && isinstr(pathname, "/usr/bin")) {
tm[name] = local_clock_ns(); } }
probe syscall.stat.return, syscall.access.return, lookup.return
{ if(pid() == target() && tm[name]) {
times[name] <<< local_clock_ns() - tm[name];
delete tm[name];
} }
' -c 'python stat-access.py'
结果如下:
COUNT AVG
lookup 80018 1.67 us
stat 40106 3.92 us
access 39903 4.27 us
请注意,我在实验中禁用了SELinux,因为它会对结果产生重大影响。