今作成しているのは、WEB上で仕事の情報をメンテナンス出来るシステムです。HTMLとPerlを利用しています。
その際に、データをテキストファイルにタブ区切りで随時書き込んだり、読込んだりする事でその内容をフォーム上に表示させたりしています。動作はしているのですが、問題が出てきました。1行単位で書き出したり読込んだりしているのですが、最近データ数(件数)が増えてきましたので、処理に時間がかかり書き出しの途中で他のページに切り替えると途中までしかデータが書き出されません。いろいろなパソコンでこのシステムを利用するので、スペックの低いマシンでも、ある程度の処理の高速化を図り、なるべくこのような事が起きないようにしたいのですが良い方法はありますでしょうか。通常こういった形でシステムを作成する場合はどのような方法をとるのでしょうか?教えて下さい。掲示板はこのような仕組みで作られていると思いますが、データの数が多い場合はどのようなコードで作成されているのでしょうか?
[コード一部]
各データは変数$data[$x]に取り込んでいます。
open(FH,">$filename");
flock(FH,LOCK_EX);
for ($x=0;$x<=$count;$x++)
{
print FH $data[$x],"\n";
}
flock(FH,LOCK_UN);
close FH;
No.5ベストアンサー
- 回答日時:
#2 です。
大変遅くなりました(^^;)サンプルソースを作ってみました。
1レコード/1データである事を前提にしたテストデータを作成し、
それを、バークレーDBへ書き込む例と、バークレーDBから読み出す例です。
動作を確認して頂くために、別々のソースにしましたが、同一ソース内に書き込み, 参照があっても問題ありません。
と言うか、tie~untieの間でバークレーDBに割り当てたハッシュの内容を更新すると、
その内容が、そのままバークレーDBに記録されます。
そのため、単にハッシュ変数を操作するだけで、バークレーDBへの更新が行われる。
と考えて頂ければ良いです。
参照する場合も、バークレーDBから読み出されるので、例の様に初めに一気に読み込んで置く必要は無く、
単にハッシュを参照すれば良い事になります。
この例では、バークレーDBとしてAnyDBM_Fileを利用しています。
AnyDBM_Fileは実際には、システムで利用できるバークレーDBシステムの
どれかに割り当ててくれる機能を持つパッケージで、
実際には、SDBMやGDBMに割り当てられます。
どのパッケージが利用できるのか、不明な時にはAnyDBM_Fileを宣言するのが良いでしょう。
この例では、1レコード/1データである事を前提にしていますが、
リファレンスを利用した複雑な型のデータを取り扱う場合、MLDBMを利用する必要があります。
MLDBMを利用する場合には、useの部分を
use SDBM_File;
use MLDBM qw (SDBM_File);
use Fcntl;
などの様にして、tie文を
tie(%h, 'MLDBM', $db, O_RDWR|O_CREAT, 0666);
としてください。
MLDBMでは、利用するDBMを指定する必要があります。(省略すると、SDBMが利用されます。)
そのため、事前にどのDBMが利用できるのか、調べて置く必要があります。
----------^^^^^ ここから ^^^^^----------
#!/use/local/bin/perl
#
# テストデータを作成する。
# mk_data.pl
# created by Dpop
#
$f = "data.txt";
open(OUT, ">$f");
foreach $a (0 .. 25) {
print OUT (chr(65+$a))x 5, "\n";
}
close(OUT);
exit(0);
----------$$$$$ ここまで $$$$$----------
----------^^^^^ ここから ^^^^^----------
#!/use/local/bin/perl
#
# テストデータをバークレーDBへ保存する。
# save_db.pl
# created by Dpop
#
use Fcntl;
use AnyDBM_File;
$f = "data.txt";
$db = "data.db";
$c = 1;
open(IN, $f) or die "open error $f";
tie(%h, AnyDBM_File, $db, O_RDWR|O_CREAT, 0666);
while(<IN>) {
chop;
$h{$c} = $_;
$c++;
}
close(IN);
untie(%h);
exit(0);
----------$$$$$ ここまで $$$$$----------
----------^^^^^ ここから ^^^^^----------
#!/use/local/bin/perl
#
# バークレーDBを読み込んで表示する。
# load_db.pl
# created by Dpop
#
use Fcntl;
use AnyDBM_File;
$db = "data.db";
tie(%h, AnyDBM_File, $db, O_RDWR, 0666);
while(($key, $value) = each(%h)) {
printf("key => %-3s data => %s\n", $key, $value);
}
untie(%h);
exit(0);
----------$$$$$ ここまで $$$$$----------
サンプルコード大変助かります。本当にありがとうございます。確認次第ご報告&ご質問をお願いするかもしれませんので、宜しくお願い致します。
No.4
- 回答日時:
前回答に補足。
サンプルコードですが、うっかりミスが2ヶ所。(ぱっと書いたので粗が目立ちます。)print "処理を受け付けました。" # <- セミコロンが無い
正:print "処理を受け付けました。";
open FH, "> $filename"; # <- 上書きモードで開くとロックされていないにも関わらずファイルが消去される
正:
open FH, "+< $filename"; # 読み書きモード
flock FH, 2;
seek FH, 0, 0;
print $_ ."?n" foreach (@data);
truncate FH, tell FH; # ファイルサイズを合わせる(ファイルサイズが小さくなった時に、ファイル末尾に前のデータが残ってしまったりするので必要)
close FH;
あと、"?n"とかになっていますが、バックスラッシュで書いたので化けたようです。"¥n"等に適時読み替えてください。
以上参考まで。
No.3
- 回答日時:
時間がかかる処理をバックグラウンドで行なう為には、forkで時間のかかる処理を子プロセスとして分離し、Apacheに対する標準出力を閉じ、プロセスが終了したと騙す方法があります。
コード例にならい、@dataにデータが保存してあるとすれば、例えば次のような処理が考えられます。
--
if( my $pid = fork ){
# 親プロセスで実行される
# プログラムの応答
print "Content-Type: text/plain;charset=utf-8?n?n";
print "処理を受け付けました。"
# Apacheへの標準出力を閉じる
close STDOUT;
# 子プロセスが終了するのを待つ
wait;
}
else{
# 子プロセスで実行される
# Apacheへの標準出力を閉じる
close STDOUT;
# ファイル書き出し
open FH, "> $filename" or die "file open error";
flock FH, 2; # 排他ロック
seek FH, 0, 2; # ロック直前にポインタがずれた時に備えて
print FH $_ . "?n" foreach (@data); # ここでは単純に全行書き出している
close FH; # ハンドルを閉じるとロックも解除
}
--
バッファリング設定($|)が0(デフォルト)ならば親プロセス内で予め定めた変数(@data等)は持ち越されます。(if fork以前の部分のみ。)
これは、単純に時間のかかる処理を子プロセスにやらせているだけで、処理が速くなるわけではありません。また、処理結果をブラウザ出力に反映する事は出来ません。(処理終了を待たずにブラウザを開放している為。)
複雑になりがちな他、うっかり妙な事を書くと子プロセスが殺されずに残ったり(ゾンビプロセスとか言いますが)するので、十分なエラー判定を行なってください。また、forkは使えないサーバもありますので要注意です。
処理の高速化を考えるのならば、今回のような行ベースのデータであれば、RDBは有効な選択肢の一つです。C/S型だと導入や管理が難しい部分はありますが、SQLiteならば導入もバックアップも容易でオススメです。(大規模なものには不向きですが。)
検索をかけると、多くの情報が得られると思います。(perl fork, DBD::SQLite等)
この回答への補足
ご返答ありがとうございます。お返事遅くなりまして申し訳ございません。M(_ _)M
恥かしながら、すぐに教えて頂いた内容が理解出来ずですので、一度コードを自分でも作ってみて確認してみたいと思います。再度質問をさせて頂くかと思いますが、よろしくお願い致します。
No.2
- 回答日時:
Web屋です。
OkWebの様なサイトを設計, 開発しています。同業者かな?
こう言う場合は、DBでしょう。
DBと言っても、RDBではなくバークレーDBです。
Perlの標準パッケージに、バークレーDBとやり取りするための機能が用意されており、
tie命令でハッシュ変数を結びつけて(「tie変数」なんて呼びます。)挙げます。
後は、普通にハッシュ変数を利用するだけでDBへ書き込まれたり、
DBから読み出されたりします。
テキストファイルと違ってDBですので、処理は高速だし、
ファイル内容全てを予め読み込んで置く必要はありません。
ハッシュ変数に単純にアクセスすれば良いだけの事です。
現在、配列にデータを取り込んでいると言う事なので、
これを全てハッシュ変数に置き換える必要がありまずか、
それだけの価値はあると思います。
サンプルソースは。。。
今適当なソースが見当たらないので、後ほど適当なソースをアップしましょう。
閉じずに、もう少し待っていてください。
この回答への補足
返事が遅くなり申し訳ありません。解答ありがとうございます。実は全くのPerl初心者ですので、教えて頂いた内容がすぐに理解出来ずです(>_<!)
しかし、時間がかかるかもしれませんが、バークレーDBに関して調べてみます。それからまた質問を挙げさせて頂きます。ありがとうございまいた。閉じずに置いておきますので、引き続きアドバイスお願いします。
No.1
- 回答日時:
一般的な掲示板では、スレッドごとに別のログファイルを使うとか、一定記事数(60行くらいが多いでしょうか。
最大でも100行くらいですね)に古いデータを過去ログとして別の場所に待避するなどでしょう(うちで使っている掲示板は、スレッドごとに別ファイルを使用しています)。しかし、この場合はあまりログを過去ログとするケースではないのではないでしょうか?
簡単に考えうるのは、一つの記事ごとに別のファイルを使うとか、一定記事数ごとに、記事を保存するファイルを変えるとかではないでしょうか?(記事数の3桁目をファイル名に使用するなど)
この回答への補足
ご返答ありがとうございます。
例えばお答えいただいたように一定の件数(例えば100行中60行分)を別のファイルに変える事で書き込みや読み込みの処理速度は1つのファイルにするよりも早くなるのでしょうか。出来れば、1つのフォーム内で全ての件数(100行分)を一覧として表示させたいのですが・・・。分かりにくくてごめんなさい。M(_ _)M
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) CSVファイルがカンマ区切りにならない。対処法を教えていただきたいです。 仕事でSMS一斉送信ができ 2 2022/07/01 21:24
- その他(プログラミング・Web制作) Windowsのマクロプログラムで、こんなことできますか? 3 2022/06/28 14:30
- Excel(エクセル) 【VBA】指定フォルダに格納中のテキストファイルをエクセルで処理し結果のエクセルを新規フォルダに保存 1 2022/03/25 14:19
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- PHP htmlspecialcharsが機能していないです。 バグですか? 1 2022/04/05 01:22
- HTML・CSS WEBサイトの構築。表示データとWEBデザインを分離する考え方を専門用語・業界用語では何と言うか? 8 2022/09/27 09:16
- Visual Basic(VBA) vbaエクセルマクロについて あるデータを作成し、デスクトップに.xlsx形式で保存するマクロを作成 2 2023/03/02 18:54
- CAD・DTP JWW-CADでDXF変換後の線が連動して消える 2 2023/01/13 11:09
- PHP 「ログイン機能を持たせる」説明が気難しいです。 2 2022/10/11 02:59
- Visual Basic(VBA) ExcelからAccessのテーブルに書き込む時に時間がかかる 1 2022/10/14 20:38
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CSVデータの編集の際の重複チェ...
-
perlでcsvファイルを読む(ダブ...
-
Perlで特定行から特定行までを...
-
CSVファイルのデータの行数を取...
-
awkスクリプトでダブルクォーテ...
-
ListBoxのデータを高速でファイ...
-
ExcelをCSV書き出す場合のシー...
-
C言語で特定の行を抽出する方法...
-
window.open でのファイル指定方法
-
パスから最後のディレクトリだ...
-
fgets で値が取得できない
-
ReadLineでの読み出し行を指定する
-
ファイル出力の改行コードをLFに
-
ifstream を利用した1行分のテ...
-
vba dir の相対パス
-
配列の中に重複文字列があるか...
-
オープンしたファイルで行の連結
-
perlで、後ろの行を読んで、前...
-
VBAのFileFormatで悩んでいるこ...
-
全角と半角文字が混在している...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Perlで特定行から特定行までを...
-
perlでcsvファイルを読む(ダブ...
-
BBCode削除&改行をサニタイジ...
-
Perlで空白行を削除
-
Perlの初心者です。2重ループ...
-
MATLAB std::exceptionエラー
-
ファイルの3行目までを出力したい
-
perlでファイルの比較
-
pythonでの実績データの処理プ...
-
cgiのログの書き方
-
先頭の単語が一致した時のデー...
-
書き込み時に勝手にクリアさせ...
-
エラーチェック、ファイルに特...
-
Argument "\\\\n" isn't numeri...
-
CSVファイルのデータの行数を取...
-
perl:パターンマッチを使ったif...
-
Pythonでegrep機能をつかいたい
-
batファイルでrenameができませ...
-
awkスクリプトでダブルクォーテ...
-
VBAでCSVファイルの特定行を書...
おすすめ情報