Я бы предположил, что access() был просто оболочкой для stat(), но я погуглил и нашел нашел несколько анекдотов о замене вызовов статистики "более дешевыми" вызовами доступа. Предполагая, что вас интересует только проверка существования файла, быстрее ли доступ? Это полностью зависит от файловой системы?
В Linux работает ли access() быстрее, чем stat()?
Ответы (1)
Теория
Сомневаюсь.
На нижних уровнях ядра нет большой разницы между вызовами access()
и stat()
, оба из которых выполняют операцию поиска: они сопоставляют имя файла с записью в кэше dentry и с inode (это фактическая структура ядра, inode
). Поиск — медленная операция, потому что вам нужно выполнять его для каждой части пути, то есть для /usr/bin/cat
вам нужно будет искать usr
, bin
, а затем cat
, и это может потребовать чтения с диска — поэтому иноды и дентри кэшируются в памяти.
Основное различие между этими вызовами заключается в том, что stat()
выполняет преобразование структуры inode
в структуру stat
, а access()
выполняет простую проверку, но это время мало по сравнению со временем поиска.
Реального прироста производительности можно добиться с помощью операций at, таких как 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, так как он сильно влияет на результаты.
stat
должен проверить некоторые вещи, которые не делает access
, например количество блоков. Большинство файловых систем, вероятно, хранят количество блоков в индексном узле, вместо того, чтобы проходить по B-дереву карты блоков, потому что stat-every-file в каталоге — очень распространенная операция, для которой они должны быть оптимизированы. Учитывая это, все, что нужно для ответа на запрос stat
, вероятно, исходит из одного поиска на диске для чтения индексного дескриптора.
- person Peter Cordes; 24.09.2015
access
находится в разделе man 2, поэтому я предполагаю, что это собственный системный вызов, а не оболочка libc для чего-то (так что теоретически это может быть быстрее, чем stat и т. д.) - person Colonel Thirty Two   schedule 24.09.2015access()
говорит вам, что вы можете читать/записывать/выполнять что-то, даже после того, как были задействованы какие-либо плагины контроля доступа (например, SELinux) или другие компоненты (расширенные ACL, разрешения AFS и т. д.).stat()
говорит вам о традиционных правах доступа к файлам UNIX, но они могут быть или не быть всей историей. И посколькуaccess()
[потенциально] выполняет больше работы, я действительно ожидаю, что он будет медленнее. - person Charles Duffy   schedule 24.09.2015fstat()
в 2 раза быстрее, чемpread()
. Однако на одном компьютере с малым объемом оперативной памяти и процессором MIPSfstat()
в 1,5 раза медленнее, чемpread()
. Таким образом, сообщение этого комментария заключается в том, что вы всегда должны измерять, чтобы получить конкретное время для вашей среды. - person gavv   schedule 24.09.2015