perlでの割り当て方法の比較

最近、私はperlプログラムのパフォーマンスと効率の問題を研究し始めました。そして、アイデアは一連のシンプルだが明確なベンチマークテストを公開するようになりました。 私は最も単純で最も典型的なもの-課題から始めます。 トピックが興味深い場合-私は続けます。



大きなプログラムは、割り当てなしではできません。 (それだけでなく)perlプログラムでは、データはハッシュ構造に保存されることが多く、これらのハッシュのフィールドを更新することは非常に一般的なタスクです。 もちろん、perlにはこのためのコードを書く方法がたくさんあります-そしてそれらはすべて読みやすさと美しさ、そして速度の点で異なります。 私はこれらの違いが何であるか疑問に思い、少し調査しました。



$hash



いくつかのフィールドを持つ$hash



リンクがあり、そのうちの3つを更新するとします。 これを記述する一般的な方法:
  <font color = "gray"> $ hash-> {foo} = 456;
 $ハッシュ-> {bar} = $ bar;
 $ hash-> {baz} = 'baz';

 </ font> 




ハッシュスライスを使用できます。3つのスカラー割り当て演算子の代わりに、1つのリスト割り当て演算子で同じ効果を実現できます。
  <font color = "gray"> @ $ hash {qw(foo bar baz)} =(456、$ bar、 'baz');

 </ font> 


ハッシュを割り当てることができます(内部で%$hash



指定して、他のフィールドが保存されるようにします):
  <font color = "gray">%$ hash =(%$ hash、foo => 456、bar => $ bar、baz => 'baz');

 </ font> 


最後に、ループを使用できます(これは多くの場合便利です)。
  <font color = "gray"> my%h =(foo => 456、bar => $ bar、baz => 'baz');
 $ hash-> {$ _} = q h {$ _} for qw(foo bar baz);

 </ font> 


または、マップコンストラクトの形式で同じことを記述します。
  <font color = "gray"> map {$ hash-> {$ _} = $ h {$ _}} qw(foo bar baz);

 </ font> 




最速の方法は何だと思いますか? ハッシュフィールドを更新するさまざまな方法の実行速度を比較するテストを実行します。
  <font color = "gray">#!/ usr / bin / perl

厳格な使用;
ベンチマークqw(cmpthese)を使用します。

私の$ハッシュ= {
	 foo => 'foo'、
	バー=> 123、
	 baz => undef、
 };

私の$ bar = 'bar';

 cmpthese(
	 -10、
	 {
		 h_direct => sub {
			 $ hash-> {foo} = 456;
			 $ハッシュ-> {bar} = $ bar;
			 $ hash-> {baz} = 'baz';
		 }、
		 h_list => sub {
			 @ $ hash {qw(foo bar baz)} =(456、$ bar、 'baz');
		 }、
		 h_hash => sub {
			 %$ hash =(%$ hash、foo => 456、bar => $ bar、baz => 'baz');
		 }、
		 h_for => sub {
			 my%h =(foo => 456、bar => $ bar、baz => 'baz');
			 $ hash-> {$ _} = q h {$ _} for qw(foo bar baz);
		 }、
		 h_forref => sub {
			 my $ h = {foo => 456、bar => $ bar、baz => 'baz'};
			 $ hash-> {$ _} = $ h-> {$ _} for qw(foo bar baz);
		 }、
		 h_map => sub {
			 my%h =(foo => 456、bar => $ bar、baz => 'baz');
			 map {$ hash-> {$ _} = $ h {$ _}} qw(foo bar baz);
		 }、
		 h_mapref => sub {
			 my $ h = {foo => 456、bar => $ bar、baz => 'baz'};
			 map {$ hash-> {$ _} = $ h-> {$ _}} qw(foo bar baz);
		 }、
	 });

 </ font> 




その結果は次のとおりです。
              レートh_hash h_forref h_mapref h_for h_map h_list h_direct
 h_hash 100913 / s--30%-42%-43%-53%-80%-91%
 h_forref 144297 / s 43%--17%-19%-32%-71%-88%
 h_mapref 174524 / s 73%21%--2%-18%-65%-85%
 h_for 177449 / s 76%23%2%--17%-65%-85%
 h_map 213368 / s 111%48%22%20%--58%-82%
 h_list 505768 / s 401%251%190%185%137%--57%
 h_direct 1169409 / s 1059%710%570%559%448%131%-





ご覧のとおり、最速の方法は直接割り当てです。 ハッシュスライスは2倍の速度で動作し、1サイクルの設計-さらに2〜3倍遅くなります。 マップループは、対応するforよりもわずかに高速です。

ただし、データはハッシュだけでなく配列にも保存できます。 配列の同様のテストでは、同様の結果が得られます。
  <font color = "gray">#!/ usr / bin / perl

厳格な使用;
ベンチマークqw(cmpthese)を使用します。

 my $ list = ['foo'、123、undef];

私の$ bar = 'bar';

 cmpthese(
	 -10、
	 {
		 l_direct => sub {
			 $リスト-> [0] = 456;
			 $リスト-> [1] = $バー;
			 $リスト-> [2] = 'baz';
		 }、
		 l_list => sub {
			 @ $ list [0 .. 2] =(456、$ bar、 'baz');
		 }、
		 l_for => sub {
			 my @l =(456、$ bar、 'baz');
			 $ list-> [$ _] = $ l [$ _] for 0 .. 2;
		 }、
		 l_forref => sub {
			 my $ l = [456、$ bar、 'baz'];
			 $ list-> [$ _] = $ l-> [$ _] for 0 .. 2;
		 }、
		 l_map => sub {
			 my @l =(456、$ bar、 'baz');
			 map {$ list-> [$ _] = $ l [$ _]} 0 .. 2;
		 }、
		 l_mapref => sub {
			 my $ l = [456、$ bar、 'baz'];
			 map {$ list-> [$ _] = $ l-> [$ _]} 0 .. 2;
		 }、
	 });

 </ font> 
              レートl_forref l_for l_mapref l_map l_list l_direct
 l_forref 197498 / s--11%-17%-38%-65%-86%
 l_for 222737 / s 13%--6%-30%-60%-84%
 l_mapref 237429 / s 20%7%--25%-58%-83%
 l_map 318127 / s 61%43%34%--43%-77%
 l_list 559192 / s 183%151%136%76%--60%
 l_direct 1395278 / s 606%526%488%339%150%-





3台のマシン(Windows XPではデスクトップ、FreeBSDでは2台のサーバー)でperl 5.8.8を比較しました。 特定の数値は異なりますが、比率はどこでもほぼ同じです。



PS <pre>でラップされたコードは、ここではなんとなくいように見えます。 もっときれいにする方法はありますか?



All Articles