国全体の配列からPerl互に非効率?
-
23-08-2019 - |
質問
が入ることが多いので、互Perl埋める"配列一部の情報です。私にも使用されるハッキングC++では、私がしばしばでこのようにPerlを用い、参考文献:
my @array;
getInfo(\@array);
sub getInfo {
my ($arrayRef) = @_;
push @$arrayRef, "obama";
# ...
}
の代わりにトレートバージョン:
my @array = getInfo();
sub getInfo {
my @array;
push @array, "obama";
# ...
return @array;
}
その理由はもちろん、あるい配列を作成する地元の型とそのコピーを返します。
そんなことがあったのですか。又はPerlの最適化と離れ。
解決
どのような最初の場所に配列リファレンスを返すでしょうか?
sub getInfo {
my $array_ref = [];
push @$array_ref, 'foo';
# ...
return $array_ref;
}
my $a_ref = getInfo();
# or if you want the array expanded
my @array = @{getInfo()};
dehmannさんのコメントに応じて編集します:
これは、関数の中で、通常の配列を使用し、それへの参照を返すことも可能です。
sub getInfo {
my @array;
push @array, 'foo';
# ...
return \@array;
}
他のヒント
を渡す参照し、より効率的であるが、その差は、C ++ほど大きくはありません。引数は値そのもの(つまり、意味:配列の値が)。常に(返された値はいえコピーされます)とにかく、参照によって渡されます。
質問です:それは問題ではありませんか?ほとんどの時間、それはしていません。あなたは5つの要素を返している場合は、それについて気にしないでください。あなたは100,000要素を渡す/返却している場合は、参照を使用しています。それがボトルネックだ場合にのみ、それを最適化します。
私はあなたの例を見て、あなたは私がこのようにそれを書くために使用しています何をしたいのかを考える場合:
sub getInfo {
my @array;
push @array, 'obama';
# ...
return \@array;
}
私は大量のデータを返す必要があるときにこれはの簡単なバージョンのように私には思えます。あなたが最初のコードスニペットに書かれたようsub
があなたのためにそれを行うために、のmy
外の配列を割り当てる必要はありませんがあります。とにかく、あなたはレオンTimmermans の<のhref = "https://stackoverflow.com/questionsとして時期尚早な最適化を行うべきではありません/ 546175 /返却--全体をアレイ-から-機能である - それは、非効率的な/ 546305#546305" > をお勧めします。
最後の反芻に答えるために、いいえ、Perlはこれを離れて最適化しません。それはない、実際には、配列を返すとスカラーを返すので、根本的に異なっていることができます。
あなたは、大量のデータを扱っているか、パフォーマンスが主要な関心事である場合は、あなたのCの習慣はよくあなたを提供する場合は - 彼らがする必要がないように、データ構造ではなく、構造そのものへの参照を渡して返しますコピーします。しかし、レオンTimmermansは、時間の大半を指摘したように、あなたはデータやパフォーマンスの少量を扱っていることはその大したことではないので、どのような方法でそれを行うことは最も読みやすいようです。
これは、私は通常の配列を返す方法があります。
sub getInfo {
my @array;
push @array, 'foo';
# ...
return @array if wantarray;
return \@array;
}
この方法は、それはスカラー、またはリストコンテキストで、あなたが望むように動作します。
my $array = getInfo;
my @array = getInfo;
$array->[0] == $array[0];
# same length
@$array == @array;
私はあなたがそれはあなたのコードの遅い部分である知っている限り、それを最適化しようとしないでしょう。それでも私は、サブルーチンが実際に高速であるかを確認するためにベンチマークを使用することになります。
2つの考慮事項があります。明白な一つは、あなたの配列が取得する予定ですどのように大きなですか?それは数十要素未満だ場合は、(あなたはマイクロ最適化している場合を除き、いくつかの急速に呼び出される関数のために、しかし、あなたがその最初を証明するためにプロファイリングいくつかのメモリをしなければならないと思います)サイズが要因ではありません。
それは簡単な部分です。しばしば見落とさ第二の考慮事項はインターフェースです。どのように返される配列が使用されようとしていますか?逆参照配列全体がPerlでちょっとひどいですので、これは重要です。たとえばます:
for my $info (@{ getInfo($some, $args) }) {
...
}
これは醜いです。これは、はるかに優れています。
for my $info ( getInfo($some, $args) ) {
...
}
また、マッピングとgrepをに適しています。
my @info = grep { ... } getInfo($some, $args);
しかし、あなたは個々の要素を選ぶつもりなら配列リファレンスを返すことは便利なことができます:
my $address = getInfo($some, $args)->[2];
これはより簡単です
my $address = (getInfo($some, $args))[2];
それともます:
my @info = getInfo($some, $args);
my $address = $info[2];
しかし、その時点で、あなたは@infoが本当にリストやハッシュであるかどうかを疑問視する必要があります。
my $address = getInfo($some, $args)->{address};
あなたはどうするべきではないことは、スカラーコンテキストとリストコンテキストでは配列の配列リファレンスを返すgetInfo()
持っています。これは、ユーザを驚かせるであろう配列の長さのようなスカラーコンテキストの伝統的な使用をmuddles。
最後に、私は自分のモジュールを接続します、方法::署名する、それは配列リファレンス構文を使用することなく、配列参照を渡すために妥協を提供していますので。
use Method::Signatures;
method foo(\@args) {
print "@args"; # @args is not a copy
push @args, 42; # this alters the caller array
}
my @nums = (1,2,3);
Class->foo(\@nums); # prints 1 2 3
print "@nums"; # prints 1 2 3 42
これはデータ::エイリアスでのマジックを介して行われます。
3その他の潜在的に大きな性能向上の場合は読書全体,largishファイルやスライスで配列:
- Offバッファリングとsysread()の代わりにread()(警告マニュアル
撹拌)
- 前の配列を大切にしながら最後の要素- 保存メモリ割当て
- 使用湿()を迅速に分割データのようなuint16_tグラフィックチャンネルデータ
通配列refの機能の主なプログラムへの対応を単純配列を書きだと忘れて働機能により複雑な"$@"矢->[$II]アクセス。いてC'ishである。
私は、Perlについて何がそう、これは言語に依存しない答えではありません知っています。
ある意味で、呼び出し元のプログラムにサブルーチンから配列をコピーするのは非効率的です。非効率を使用し、余分なメモリとある場所から別の場所にデータをコピーするのに要する時間に発生します。一方、最大の配列が、すべてのために、あなたは気にしないかもしれない、と優雅さ、cussednessまたはその他の理由のための配列をコピーすることを好むかもしれません。
サブルーチンが呼び出しプログラムにアレイのアドレスを渡すために効率的な解決策です。私が言うように、私はこの点でPerlのデフォルトの動作についての手掛かりを持っていません。しかし、いくつかの言語はプログラマにどのアプローチを選択するオプションを提供します。