12

質問

一般的に、特定のプラットフォームに関係なく、Perl でのCwd::cwdとの違いは何ですか? Cwd::getcwdPerl に両方があるのはなぜですか? 使用目的は何ですか?どのシナリオでどれを使用すればよいですか? (ユースケースの例をいただければ幸いです。)それは重要ですか?(私はそれらを混ぜないと仮定します。)どちらかを選択すると、移植性に何らかの影響がありますか? モジュールでより一般的に使用されるのはどれですか?

マニュアルを解釈しても、まれなケースを除いて、から呼び出すだけでcwdある`pwd`と言っていますが、実際の違いは何ですか? とにかく、これはPOSIXシステムでのみ機能します。getcwdgetcwdunistd.h

私はいつでも実装を読むことができますが、それらの関数の意味については何も教えてくれません。実装の詳細は変更される可能性があり、定義された意味ではありません。(そうしないと重大な問題である重大な変更が発生します。)

マニュアルには何と書かれていますか

PerlのCwdモジュールのマンページを引用:

これらの各関数は引数なしで呼び出され、現在の作業ディレクトリの絶対パスを返します。

  • getcwd

    my $cwd = getcwd();

    現在の作業ディレクトリを返します。

    POSIX 関数 getcwd(3) を公開するか、利用できない場合は再実装します。

  • cwd

    my $cwd = cwd();

    cwd() は、現在のアーキテクチャにとって最も自然な形式です。ほとんどのシステムでは、これは `pwd` と同じです (ただし、末尾の行ターミネータはありません)。

そしてメモセクションで:

  • 実際、Mac OS では、getcwd()関数fastgetcwd()fastcwd()関数はすべて関数のエイリアスでcwd()あり、Mac OS では「pwd」を呼び出します。同様に、abs_path()関数はのエイリアスですfast_abs_path()

OK、Mac OS 1getcwd()では と の間に違いはないことはわかっています。cwd()どちらも実際には`pwd`. しかし、他のプラットフォームではどうでしょうか? (特に Debian Linux に興味があります。 )


1 OS X ではなく、従来の Mac OS。Mac OS と OS Xの$^O値はそれぞれMacOSdarwinです。@tobyink@ikegamiに感謝します。

そして、ちょっとしたメタ質問: 非常によく似た機能を持つ他のモジュールに対して同様の質問をしないようにするにはどうすればよいですか? 実装を掘り下げる以外に、違いを発見する普遍的な方法はありますか? (現在、ドキュメントの使用目的や相違点が明確でない場合は、経験豊富な人に尋ねるか、自分で実装を読む必要があると思います。 )

4

1 に答える 1

10

一般的に言えば

cwd()アイデアは、現在の作業ディレクトリを取得するための外部の OS 固有の方法に常に解決されるということだと思います。つまり、pwdLinux、command /c cdDOS、/usr/bin/fullpath -tQNX などで実行されます。すべての例は実際のCwd.pm. はgetcwd()、利用可能な場合は POSIX システム コールを使用し、そうでない場合は にフォールバックすることになっcwd()ています。

なぜ私たちは両方を持っているのですか?現在の実装では、エクスポートするだけgetcwd()でほとんどのシステムで十分だと思いますが、「システムコールが利用可能な場合はそれを使用し、それ以外の場合は実行する」というロジックがcwd()一部のシステムで失敗する可能性がある理由を誰が知っていますか (たとえば、Perl 5.6.1 の MorphOS ) 。 .

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ソースを読む

ソース ( Cwd.pmCPAN など) を見ると、名前が示すように、 Linux のcwd()呼び出しがマップされていることがわかります。_backtick_pwdpwd

からのスニペット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;
    }
}

パフォーマンス ベンチマーク

最後に、2 つの違いは、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 は含まれていません)。奇妙なプラットフォームのリスト)。

于 2014-08-25T11:26:43.960 に答える