Data::Dumper(Data::Dumperにこだわるわけではないのですが)を使って無名配列or無名ハッシュの値(40万行程度あると仮定。
例)
$VAR1 = {
'aaa' => {'get' => '1','all' => '0'},
'bbb' => {'get' => '1','all' => '1'},
}
といった形)を変更後、保存する場合、その配列orハッシュ全体を読み込んで保存する形になるのでしょうか、それとも、配列orハッシュ全体を読み込まず各値に対するアドレスから実体(リファレンス/シンボリックリファレンスの概念が明確にわかってないのですが)へアクセスして値を変更=そのまま保存するようになのでしょうか。
諸先輩or先生方、お手数ですがこの辺りの仕組みについてご教授願えますと幸いです。宜しくお願い致します。
No.5ベストアンサー
- 回答日時:
結局やっていることは、
・以前にダンプしておいた情報を復元する
・処理する
・新たにダンプする
ということであり、ファイルの読み込みと書き込みは抱えている
ハッシュのデータ丸ごとです。40万行あるファイルならそれだけの量を
読み書きしています。
データベースを使う場合は、データベースに必要な情報だけをもらったり
与えたりするので、ファイルの読み書きという点で言えば格段に
少なくなるはずです。
もし現状のファイル丸ごと読み書きによる時間のロスが気になるということなら
データベースを使うことを検討してもいいと思います。
また、普通のテキストファイルで読み書きするにしても、Data::Dumperの
出力書式はこの種の目的には冗長ですから、自分で適当にフォーマットを決めた上で
読み書きすれば多少は改善できるかもしれません。
詳細な処理を訊くよりは、どういうデータをどのように処理したいのか
(他の質問とあわせて考えるとURLの参照記録?)を書いたほうが
良いアドバイスがもらえるでしょう。
貴重なアドバイス有難うございます。
やはりDBを使う事で必要な情報のみの読み書きになり、軽い処理になるんですね。
後、Data:Dumperでの出力処理は、冗長なんですか。その為、よくフリーのCGIでは<>でデータを挟んで処理しているケースが多いんでしょうかね・・・。
Data::Dumperが冗長という事で、ソースを見てみたいのですが、適当に検索してみたのですが、思うようにソースの味方がわかりませんでした。どのようにすれば見れるかなど、恐縮ですがご教授願えませんでしょうか。
No.6
- 回答日時:
Data::Dumperをいじってその書式を変えようってんですか?
そりゃあいくらなんでも努力の方向を間違えているような気がします。
とりあえず、簡単に ',' で区切ったリストで表現した場合と
Data::Dumper の出力を使った場合でどのくらい違うのか試してみました。
面倒なので、読み出してそのまま出力するだけのものです。
が、データの更新はどちらの方法でも同じなのでやらないでもいいでしょう。
#urlには ',' が含まれる可能性があるのであまりよろしくありませんが
#あくまで目安を得るためということで。
テストスクリプトは以下の通りです。
40万レコードでは試してませんが、数字をいじればすぐ試せます。
#!/usr/bin/perl
# -*- coding: utf8 -*
use strict;
use warnings;
use Fatal qw(:void open close);
use Data::Dumper;
my $csv_file = 'basedata.txt';
my $dumped_file = 'hashdata.txt';
sub make_randomstr_generator {
my @basechars = split q{}, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
return sub {
my @t;
foreach (0 .. (rand()*10 + 7)) {
push @t, $basechars[int(rand() * scalar(@basechars))];
}
return 'http://' . (join q{}, @t) . '.com';
}
}
sub make_data_file {
my $item_count = shift || 10000;
my $gen = make_randomstr_generator;
open my $fh, '>', $csv_file;
printf {$fh} "%s,%s,%d,%s,%d\n", $gen->(), 'all', 0, 'cate', 0 for (1..$item_count);
close $fh;
open my $ifh, '<', $csv_file;
my $h_ref = {};
while (defined(my $l = <$ifh>)) {
chomp $l;
my @f = split q{,}, $l;
my $url = shift @f;
$h_ref->{$url} = { @f };
}
close $ifh;
open my $ofh, '>', $dumped_file;
print {$ofh} Dumper($h_ref);
close $ofh;
}
##########
sub use_csv_version {
open my $ifh, '<', $csv_file;
my $h_ref = {};
while (defined(my $l = <$ifh>)) {
chomp $l;
my @f = split q{,}, $l;
my $url = shift @f;
$h_ref->{$url} = { @f };
}
close $ifh;
open my $ofh, '>', "$csv_file.1";
foreach my $key (keys %{$h_ref}) {
printf {$ofh} "%s,%s,%d,%s,%d\n",
$key, 'all', $h_ref->{$key}{all}, 'cate', $h_ref->{$key}{cate};
}
close $ofh;
}
sub do_dump_version {
my $h_ref = {};
#require $dumped_file;
our $VAR1 = "";
do $dumped_file;
$h_ref = $VAR1;
open my $ofh, '>', "$dumped_file.1";
print {$ofh} Dumper($h_ref);
close $ofh;
}
#####
use Benchmark qw(:all);
make_data_file(100000);
my $count = 10;
timethese($count, {
'Non-Dump version.' => sub { use_csv_version},
'Dump version.' => sub { do_dump_version },
});
実行結果:
Benchmark: timing 10 iterations of Dump version., Non-Dump version....
Dump version.: 998 wallclock secs (616.11 usr + 4.51 sys = 620.62 CPU) @ 0.02/s (n=10)
Non-Dump version.: 286 wallclock secs (135.16 usr + 0.58 sys = 135.73 CPU) @ 0.07/s (n=10)
カッコの中身の数字が大体の処理時間の目安と見てください。
出力ファイルのサイズは次の通り
2007/12/19 01:51 3,850,858 basedata.txt.1
2007/12/19 01:46 19,903,454 hashdata.txt.1
どんだけ冗長かはわかっていただけると思います。
No.4
- 回答日時:
私の理解力不足で、力になれないな感じがしてきました、申し訳ないです…。
どなたかフォローして頂けるとありがたいんですけど…。
一応、思う事を書きます。
>open(F,"> $dumpfile") ;
>print F Dumper(\%hash);
>close(F);
上記のコードでファイルに書き込まれたものは、
%hash のデータを Perl で実行可能なコードで表現した文字列であり、
メモリにある %hash とは何の関係もありませんよね?
で、そのコードをディスクに書き込んだわけですよね?
その後、
>my$hash_ref = require 'dump2.txt';で読み込み
これで、dump2.txt 内のコードが実行されて、新たに $hash_ref に全てが復元されて、新しいメモリが割り当てられます。
(一部って言うのは無理なんじゃないかと思います、dump2.txt をテキストとして直接いじれば別でしょうけど)。
>リファレンスを使って実体を直接変更するという事は、毎回ハッシュ全体
>(foreachかwhillによっても読み込む行か全体かが違うようですが、変更時には既にハッシュ全体を読み込んでいる状態?)
>を保存するのか
リファレンスと言うのは、
配列等のメモリアドレスの様な物を格納した単なるスカラー値ですので、
リファレンスを使ったからって特別何かが変わるわけではありません。
そもそも、
>my %hash;
>foreach my $a ( @allurl ) {
>foreach my $b ( @cate ) {
>$hash{$a}{$b} = '0';
>}
>}
$hash{$a} は無名ハッシュのリファレンスなんで、リファレンス以外に参照できません。
で、データが復元されているのは require の時点であって、
呼び出されたときにメモリが割り当てられるわけではないと思います。
最後にしつこいようですが、
●Data::Dumper が出力する物は単なるPerlのコード。
●require はコードを実行してコードの最後に評価された値を返すので、
Data::Dumperで出力したテキストを require した場合、
他の何物とも無縁の新しいデータが生成される。
あと、余計なお世話かも知れませんが、
use strict;
した方が良いでしょう、また
$a と $b は使うのは止めといた方がよいです。
*Perl の内部までは私も良く分かっていませんので、間違いがあるかも知れません、すみません。
間違っていたらどなたかツッコミよろしくお願いします。
No.3
- 回答日時:
>リファレンスを使っての保存時でも、結局配列全体を保存し直し・・と言う事になるのでしょうか。
書かれている「保存」の意味が良く理解できません。
私が思っている、Data::Dumper を使ったデータの保存って言ったら、
ハッシュやら配列やらオブジェクトを文字列化したものを、テキストとして、
ファイルやらデータベースに格納するって事だと考えていますが、
そうではないのでしょうか?
全体とか部分的にといった考え方が良く理解できません。
Data::Dumper 出力された物を、テキストデータとして扱うといった意味ですか?
Data::Dumper で出力した物をどう保存していて、
どんな風に再利用しているのか簡単なコードを見せて頂けたら
何かアドバイスできそうな気がするんですが…。
この回答への補足
私もテキストとして、ファイルやらデータベースに格納すると考えております。
全体や部分的にと言う事について、ここでは重複いたしますので、下記のスクリプト内容を前提に最後に再度私の意図した質問を掲載させて頂いております。
よろしければご参照頂けましたら幸いです。
宜しくお願い致します。
・ファイルの内容
$ cat testfile1
--testfile1の内容----------
aaaa
bbbb
cccc
--ここまでで40万行あると仮定----------
・スクリプト内容表示
$ cat dump-test.cgi
--ここからdump-test.cgiの内容----------------
use Data::Dumper;
$Data::Dumper::Indent = 1;
$dumpfile='dump2.txt';
use Data::Dumper;
my @allurl;
while (chomp($_ =<STDIN>)){
push(@allurl,"$_");
}
close(STDIN);
my @cate = qw(all cate);
my %hash;
foreach my $a ( @allurl ) {
foreach my $b ( @cate ) {
$hash{$a}{$b} = '0';
}
}
open(F,"> $dumpfile") ;
print F Dumper(\%hash);
close(F);
my$all = 'all';
my$cate = 'cate';
my$hash_ref = require 'dump2.txt';
foreach my $c ( keys %{$hash_ref} ) {
if(exists($hash{$c}) ){
$hash_ref->{$c}{$cate} = '1';
}else{
$hash_ref->{$c}{$cate} = '0';
}
}
open(F,"> dump2.txt") ;
print F Dumper($hash_ref);
close(F);
--ここまで---------------------------
・実行
$ cat testfile1 | perl url-dump-test.cgi
サーバーのシェル上からパイプを使ってtestfile1の中身を渡しているのですが、一度保存したもの(ここの部分は毎回ではなく別スクリプトでもよいのですが)をmy$hash_ref = require 'dump2.txt';で読み込みそれ以降の条件分岐箇所で何かしらの判定をして
$hash_ref->{$c}{$cate} = '1';
か
$hash_ref->{$c}{$cate} = '0';
と変更し保存したい場合、リファレンスを使って実体を直接変更するという事は、毎回ハッシュ全体(foreachかwhillによっても読み込む行か全体かが違うようですが、変更時には既にハッシュ全体を読み込んでいる状態?)を保存するのか、値の変更箇所だけを保存(書き換え)できるのか・・の所がよくわかってないのですけれども、ここの部分についてお分かりでございますでしょうか。ご教授頂けますと幸いです。また結果的にはリファレンスを使わなくても変更時にはハッシュなり配列なりの全体を保存するという事なのでしょうか。
またDB(mysql,postgresなどを想定)での保存の場合は、この場合、
$hash_ref->{$c}{$cate} = '1';
か
$hash_ref->{$c}{$cate} = '0';
の値の変更箇所だけを変更できるという概念なのでございますか?お恥かしながらご存知なようでしたら合わせてご教授頂けますと幸いです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP 配列の値の更新方法について 1 2022/08/05 09:49
- Excel(エクセル) エクセルのマクロについて教えてください。 1 2023/02/21 09:28
- C言語・C++・C# C言語初心者 ポインタについて、お助けください、、 2 2023/03/15 23:50
- Excel(エクセル) エクセルVBA、ファイル名をセルの値で保存の方法を教えてください。 おそれいります。こちらで数々のエ 6 2023/06/30 22:17
- Perl perlをバージョンアップしたら、今まで正常に動いていたプログラムが、エラーになってしまった 3 2022/10/05 15:44
- システム CSVファイルのマッピング処理の省力化 1 2022/11/24 00:01
- Excel(エクセル) Excelのマクロコードについて教えてください。 1 2022/03/27 10:47
- C言語・C++・C# pythonのファイルの並びでの読み込みとリストについて 4 2022/04/13 03:52
- その他(プログラミング・Web制作) pythonでクラスで複数のメソッドを利用する方法 2 2022/04/15 04:17
- Excel(エクセル) エクセルのマクロについて教えてください。 1 2023/02/03 13:18
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ハッシュ検索はなぜ速い
-
列挙型と連想配列の違いを教え...
-
SSLとMD5について
-
VBAにハッシュ関数はないのです...
-
ハッシュマーク以降のアドレス取得
-
VBのReturnの使い方
-
CSVファイルの特定の行だけを読...
-
エクセルの当番表を作っていま...
-
GIFアニメをループさせたくない
-
VBA Boxが空白の場合のメッセー...
-
画面を強制的に再描画させる方法
-
繰り返し処理で50音順にする方法
-
Pro Tools の 波形を伸ばす方...
-
vbscriptでIE自動入力(途中で...
-
フローチャートを教えてください
-
VBAで3秒だけ時間を止めたい
-
リストボックスに縦スクロール...
-
Python IndexError:list index ...
-
VB2010でCSVファイルの読み込み
-
流れ図(フローチャート)が分か...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ハッシュ検索はなぜ速い
-
文字列を変数名として扱う方法
-
チェックデジットについて
-
列挙型と連想配列の違いを教え...
-
まったく同じファイルのハッシ...
-
ハッシュ値が一致したデータは...
-
英語でのシャープとコメの呼び...
-
ハッシュのハッシュを実現したい。
-
データベースでユーザーのパス...
-
UTF-8で書かれたJSPの日本語文...
-
Perlは戻り値で、ハッシュや配...
-
perlで配列名を動的に作り出したい
-
ハッシュリストって単にハッシ...
-
短いハッシュの作り方
-
重複ファイルを削除したいので...
-
*(アスタリスク)の意味
-
連想配列のサイズ制限
-
python の素朴な疑問
-
多次元配列から重複を削除
-
一意(ユニーク)かつ、ソート...
おすすめ情報