2

As far as I know, in Perl, we can call a subroutine from a Module by using these techniques:

  • Export subroutine foo, import the module which has this subroutine. Finally call it in your perl script.
  • Create an Object of that Module in your perl script finally call foo using that Object.
  • Directly call foo using its path, like this myDir::Module::foo();.

If I am always confused which is better way of calling a subroutine foo. If I have a dynamic script, which I run from the browser and not command line, which approach one should go for so that the script takes less time.

Thanks.

4

2 に答える 2

6

Perl でコードを呼び出す最速の方法と最良の方法には違いがあります。


編集:simbabquesの回答もご覧ください。彼は特に #1 と #3 の違いと、どちらを使用するかについて説明しています。


#1, #3: 関数呼び出し

#1 と #3 は同一です。サブルーチンには、グローバルに表示される名前空間で一意の名前があります。多くの名前が、エイリアスまたはモジュールのインポートを介して 1 つのサブルーチンにマップされる場合があります。

呼び出している関数の名前がコンパイル時にわかっている場合、サブルーチンはコンパイル時に解決されます。これは、関数を自発的に再定義しないことを前提としています。正確な関数が実行時にしかわからない場合、これはハッシュ ルックアップだけです。

関数を呼び出すには、次の 3 つの方法があります。

foo(@args);
&foo(@args);
@_ = @args; goto &foo;

1 番目 (中かっこはオプションの場合もあります) がデフォルトであり、サブ プロトタイプに対して引数を検証します (プロトタイプを使用しないでください)。また、コール スタック フレーム全体 (多くの有用なデバッグ情報を含む) が構築されます。これには時間がかかります。

2 番目は、プロトタイプの検証をスキップし、自分が何をしているかを理解していることを前提としています。これはわずかに高速です。ずさんなスタイルだと思います。

3番目はテールコールです。これは、戻り値 の現在のサブルーチンから戻りますfoo。プロトタイプは無視され、現在のコール スタック フレームを再利用できるため、これは高速です。これはあまり役に立ちませんし、構文も醜いです。コードをインライン化すると、約 1 桁速くなります (つまり、Perl では、再帰よりもループを優先します ☹)。

#2: メソッド呼び出し

OO の柔軟性は、大きなパフォーマンス プライスを伴います。メッセージを呼び出すオブジェクトの型は実行時までわからないため、実際のメソッドは実行時にしか解決できません。

これは、編集されたパッケージ内$foo->bar()の関数を検索することを意味します。そこで見つからない場合は、親クラスで検索されます。これは遅いです。オブジェクト指向を使いたい場合は、階層が浅い(→参照が少ない)ことに注意してください。また、Perls のデフォルトのメソッド解決順序は通常とは異なることに注意してください。bar$foobless

通常、型がわかっている場合でも、メソッド呼び出しを関数呼び出しに減らすことはできません。

if$fooが classFooでありFoo::bar、サブである場合Foo::bar($foo)、メソッドの結果がスキップされ、機能する可能性さえあります。ただし、これはカプセル化を壊し、Fooサブクラス化すると壊れます。また、が定義されてFooいない場合、これは機能しませんbarが、メソッドは親クラスで定義されています。

必要なパフォーマンスが得られないことがベンチマークから明らかになるまで、私は一般的にオブジェクト指向を支持します。

于 2013-02-07T11:37:43.553 に答える
4
  • サブルーチン foo をエクスポートし、このサブルーチンを持つモジュールをインポートします。最後に、perl スクリプトで呼び出します。

これを行うには、sub を実装するmodule/でExporterを使用します。およびpackageを介してモジュールに何をエクスポートするかを伝えます。モジュールの場合、コンパイル時に現在の名前空間にインポートされます。以下のステートメントは同等です。@EXPORT_OK@EXPORTuse

# This is the same...
use Module;
# ... as this

BEGIN {
  require Module;
  Module->import();
}

メイン スクリプトで使用するものがある場合、または頻繁に使用するものがある場合は、これを行います。いくつかの例はList::UtilData::Dumperまたはuse feature 'say'です。もちろん、他のモジュールでも使用できます。

use Data::Dumper;
use List::Util qw(max);
use feature qw(say);

my @foo = (1, 2, 3, 4, 5, 23);
print Dumper \@foo;
say max(@foo);

問題は、ここで名前空間を「汚染」することです。必要に応じてこれを行いますが、これはコンパイル時に行われるため、条件付きではないことに注意してください。あなたは言うことができません

if ($foo) {
  use Some::Module 'foo';
  foo($foo);
} else {
  use Something::Else 'bar';
  bar();
}

Some::Module Something::Elseコンパイル時の両方でロードされるため、プログラムが消費する時間とメモリが増加します。条件はもちろん機能しますが、効率的ではありません。

  • Perlスクリプトでそのモジュールのオブジェクトを作成し、最終的にそのオブジェクトを使用してfooを呼び出します。

これが OOp アプローチです。(前述のように)他の方法とは比較できません。オブジェクトのメソッドをインポートする必要はありません。useまたは(上記参照) を使用してクラス (モジュール) をロードrequireし、インスタンスを作成して、そのメソッドを好みに合わせて使用​​するだけです。ただし、そのためにはオブジェクト指向モジュールが必要です。それがどのように機能するかに興味がある場合は、まず perlootutを見てください。

  • この myDir::Module::foo(); のように、そのパスを使用して foo を直接呼び出します。

実際にはそのパスではなく、その名前 (スペース) です。たとえば、Data::Dumper は、 dirのどこかにDumper.pmあるフォルダーにあります。しかし、それはそれほど重要ではありません。Datalib

最初のアプローチとの主な違いは、インポート部分を省略していることです。これは、特定のモジュールを条件付きでロードするものを構築したい場合、または巨大な (おそらくレガシー) アプリケーションを使用していて名前空間を汚染したくない場合に役立ちます。

if ($order_has_some_condition) {
  require Very::Long::NameSpace::For::This::Condition::Module;
  Very::Long::NameSpace::For::This::Condition::Module::do_stuff_with_an_order($order);
}

このコード片が 2,000 行のレガシー サブルーチンにあり、多くの処理が行われていると想像してください。この場合、そのほとんどは呼び出されません。useこの巨大なコード片で処理されるおそらく 100 の異なるケースのそれぞれでモジュールを使用できるようにするために、モジュールを使用したくありません。代わりに、本当に必要な場合にのみロードしたいと考えています。ここでrequireモジュールを作成し、完全な名前を使用してそのサブを直接呼び出します。

結論として、最初の方法と 3 番目の方法の両方にメリットがあります。どちらも存在する必要があり、適切であれば両方を使用する必要があります。場合によっては単なる風味ですが、他の場合は決定するのが理にかなっています。2 番目の OOp アプローチは、まったく別のものです。

実際の速度の違いはなく、ボロディンが言ったように、Perl は高速です。もちろん、詰め込みをしなければimport、輸入に「お金を払う」必要はありません。10 行のスクリプトでは、それは問題ではありません。1 つの巨大なファイルに数千行のコードと多くのユース ケースが含まれる可能性があるレガシー ソフトウェアでは、これは非常に重要です。

これがあなたの決定に役立つことを願っています。

于 2013-02-07T11:36:16.710 に答える