とあるエンジニアの闇歴史帳

コピペで使える便利Wiki ※現在構築中です。

ユーザ用ツール


perl:hash_speedup

差分

このページの2つのバージョン間の差分を表示します。

この比較画面にリンクする

perl:hash_speedup [2017/12/14 20:18]
perl:hash_speedup [2020/06/23 14:10] (現在)
行 1: 行 1:
 +======  ハッシュを高速に処理する - Perl ======
 +~~socialite~~
 +<note important>この記事は2007年03月08日に書かれた物です</note>
 +
 +ハッシュに大量のデータを挿入する際、プログラムの動作を出来る限り早く(高速に)、処理を軽くしたい。実は一行付け足すだけで、かなり違ってくる技がある。
 +
 +**keys**は本来ハッシュのキーを取り出す際に利用するのだが、これから登録するハッシュのキーの数をあらかじめ宣言する機能を持つ。これを行うことでPerl内部の処理が1ステップ減り、大量のデータを追加する際、高速な動作が期待できる。
 +
 +===== サンプル =====
 +<code perl>
 +;#
 +;#ハッシュの処理速度を上げる
 +;#
 +
 +my %hash = ();
 +
 +#-- ここで個数を指定する --#
 +keys(%hash) = 30000;           #この場合は3万件
 +
 +open(DAT, 'ken_all.txt') or die($!);
 +while(<DAT>){
 +    chomp;
 +    my ( $post_cd, $address ) = split(/\t/);
 +    $hash{$post_cd} = $address;
 +}
 +close(DAT);
 +</code>
 +
 +===== 検証 =====
 +原理はシンプル。 例外もあるが、原則としてPerlはハッシュに値が追加されるたびにメモリの確保を行っている。この作業を毎回行うよりも、冒頭で一括して行う方が速いため、動作が軽くなるのである。本当に軽くなるか、実際に実験を行ってみた。
 +
 +ここでは1,000件、5,000件、30,000件のテストデータを用意した。[[http://www.post.japanpost.jp/zipcode/download.html|郵政公社が公開している郵便番号のデータ]]を加工し、ランダムに抽出した物である。
 +
 +テストデータは右記からダウンロード可能。
 +{{:perl:ken_all.zip|}}
 +
 +<code>
 +○1,000件
 +Benchmark: timing 1000 iterations of NON_SET, SET...
 +   NON_SET:  4 wallclock secs ( 3.99 usr +  0.00 sys =  3.99 CPU) @ 250.63/s (n=1000)
 +       SET:  3 wallclock secs ( 3.60 usr +  0.01 sys =  3.61 CPU) @ 277.01/s (n=1000)
 +
 +○5,000件
 +Benchmark: timing 1000 iterations of NON_SET, SET...
 +   NON_SET: 20 wallclock secs (19.87 usr +  0.12 sys = 19.99 CPU) @ 50.03/s (n=1000)
 +       SET: 18 wallclock secs (18.30 usr +  0.08 sys = 18.38 CPU) @ 54.41/s (n=1000)
 +
 +○30,000件
 +Benchmark: timing 1000 iterations of NON_SET, SET...
 +   NON_SET: 121 wallclock secs (119.55 usr +  0.93 sys = 120.48 CPU) @  8.30/s (n=1000)
 +       SET: 111 wallclock secs (110.51 usr +  0.58 sys = 111.09 CPU) @  9.00/s (n=1000)
 +</code>
 +
 +実行結果を見て分かる通り、1000件などデータ件数が少ないうちは大差ないが、数万件レベルになってくると如実な違いが見て取れる。
 +
 +
 +==== ベンチマーク測定用コード ====
 +
 +<code perl>
 +#!/usr/bin/perl
 +
 +;#
 +;#ハッシュのベンチマーク
 +;#
 +
 +use Benchmark;
 +
 +#--------------------------------------------#
 +#ベンチマーク
 +#--------------------------------------------#
 +timethese(
 +    1000, {
 +          'SET'     => 'set1();'
 +        , 'NON_SET' => 'set2();'
 +
 +    }
 +);
 +
 +#--------------------------------------------#
 +#都度メモリ確保
 +#--------------------------------------------#
 +sub set1{
 +    my %hash = ();
 +
 +    open(DAT, 'ken_all.txt') or die($!);
 +    while(<DAT>){
 +        chomp;
 +        my ( $post_cd, $address ) = split(/\t/);
 +        $hash{$post_cd} = $address;
 +    }
 +    close(DAT);
 +
 +}
 +
 +#--------------------------------------------#
 +#冒頭で一括してメモリ確保
 +#--------------------------------------------#
 +sub set2{
 +    my %hash = ();
 +
 +    keys(%hash) = 30000;
 +
 +    open(DAT, 'ken_all.txt') or die($!);
 +    while(<DAT>){
 +        chomp;
 +        my ( $post_cd, $address ) = split(/\t/);
 +        $hash{$post_cd} = $address;
 +    }
 +    close(DAT);
 +}
 +</code>
 +
 +
 +===== 参考文献 =====
 +[[http://www.amazon.co.jp/exec/obidos/ASIN/4873112028/ichikorocom-22/ref=nosim/|Perlクックブック〈VOLUME1〉]]
 +
 +===== 関連書籍 =====
 +{{amazon>jp:4873113008}}
 +<html><p style="clear:both"></p></html>
 +
 +{{amazon>jp:4798139815}}
 +<html><p style="clear:both"></p></html>
 +
 +{{tag>CGI・Perl例文集 Perl 連想配列 ハッシュ Benchmark ベンチマーク}}
 +~~socialite~~
  

関連ページ