Ответ 1
Вообще говоря,
Я думаю, идея состоит в том, что cwd()
всегда решает внешний, специфичный для ОС способ получения текущего рабочего каталога. То есть, запуская pwd
в Linux, command /c cd
в DOS, /usr/bin/fullpath -t
в QNX и т.д. - все примеры взяты из фактического Cwd.pm
. Предполагается, что getcwd()
использует системный вызов POSIX, если он доступен, и возвращается к cwd()
, если нет.
Почему у нас есть оба? В текущей реализации я считаю, что экспортировать только getcwd()
было бы достаточно для большинства систем, но кто знает, почему логика "если syscall доступна, используйте ее, иначе запустите cwd()
" может выйти из строя в какой-либо системе (например, на MorphOS в Perl 5.6.1).
В Linux
В Linux cwd()
запустится `/bin/pwd`
(фактически выполнит двоичный файл и получит его вывод), а getcwd()
выдаст системный вызов getcwd(2)
.
Проверяется фактический эффект через strace
Можно использовать strace(1)
, чтобы увидеть, что в действии:
Использование cwd()
:
$ strace -f perl -MCwd -e 'cwd(); ' 2>&1 | grep execve
execve("/usr/bin/perl", ["perl", "-MCwd", "-e", "cwd(); "], [/* 27 vars */]) = 0
[pid 31276] execve("/bin/pwd", ["/bin/pwd"], [/* 27 vars */] <unfinished ...>
[pid 31276] <... execve resumed> ) = 0
Используя getcwd()
:
$ strace -f perl -MCwd -e 'getcwd(); ' 2>&1 | grep execve
execve("/usr/bin/perl", ["perl", "-MCwd", "-e", "getcwd(); "], [/* 27 vars */]) = 0
Чтение Cwd.pm
source
Вы можете посмотреть источники (Cwd.pm
, например, в CPAN) и посмотреть, что для Linux cwd()
отображается вызов на _backtick_pwd
, который, как следует из названия, вызывает pwd
в обратных циклах.
Вот фрагмент от Cwd.pm
, с моими комментариями:
unless ($METHOD_MAP{$^O}{cwd} or defined &cwd) {
...
# some logic to find the pwd binary here, $found_pwd_cmd is set to 1 on Linux
...
if( $os eq 'MacOS' || $found_pwd_cmd )
{
*cwd = \&_backtick_pwd; # on Linux we actually go here
}
else {
*cwd = \&getcwd;
}
}
Тест производительности
Наконец, разница между двумя заключается в том, что cwd()
, который вызывает другой двоичный файл, должен быть медленнее. Мы можем сделать какой-то тест производительности:
$ time perl -MCwd -e 'for (1..10000) { cwd(); }'
real 0m7.177s
user 0m0.380s
sys 0m1.440s
Теперь сравните его с системным вызовом:
$ time perl -MCwd -e 'for (1..10000) { getcwd(); }'
real 0m0.018s
user 0m0.009s
sys 0m0.008s
Обсуждение, выбор
Но поскольку вы обычно не слишком часто запрашиваете текущий рабочий каталог, обе опции будут работать - если только вы не можете запускать какие-либо процессы по какой-либо причине, связанные с ulimit
, ситуацией с памятью и т.д.
Наконец, что касается выбора того, какой из них использовать: для Linux я всегда использовал бы getcwd()
. Я полагаю, вам нужно будет сделать свои тесты и выбрать, какую функцию использовать, если вы собираетесь написать переносную часть кода, которая будет работать на какой-то действительно странной платформе (здесь, конечно, Linux, OS X и Windows не входят в список странных платформ).