• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:最も速いデータ読込は?)

最速のデータ読み込み方法とは?

このQ&Aのポイント
  • VisualStudio 2005 C#でデータを読み込み、グラフにプロットする方法について教えてください。
  • 現在、テキストファイルのデータを行単位で配列に格納し、指定条件に基づいてプロット処理を行っています。
  • しかし、ボタンクリックイベントでの処理に時間がかかってしまいます。より効率の良い方法はありますか?

質問者が選んだベストアンサー

  • ベストアンサー
  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.4

>(4)1行目から最終行まで探索し、 いわゆるシーケンシャルサーチのようですが 10万行あれば10万回の検索が発生し 条件が100個あるとするなら1000万回の比較が発生しますよね? 2分探索を使えばLog2(10万)=16.6 つまり17 * 100 = 1700回の比較で済みます。 (1)予めテキストデータを全て行単位で配列に格納しておく (2)プロットするデータの条件を決定(任意) (3)配列のデータをソート (4)プロット処置開始 (5)2分探索で目的のデータを検索 (6)一致するものがあれば描画 あと6(描画)はネックにはなっていませんか? もしボトルネックになっているとするなら毎回描画するのではなく バックサーフェースを作り(System.Drawing.Graphicsを別に作成) そこで全てを描画しきってから Graphics.DrawImageで転送すると速くなるでしょう。 ボトルネックを調べるにはQueryPerformanceCounterを使ってください。 その処理に何クロックかかっているかがわかります。 http://www.divakk.co.jp/aoyagi/csharp_tips_tracetime.html

kourogi_07
質問者

お礼

ご返答ありがとうございます。 皆さんのアドバイスを取り入れた上で、その成果をQueryPerformanceCounterで確認したいと思います。

その他の回答 (7)

noname#140971
noname#140971
回答No.8

補足: UNIX C、Windows C、Windows VB でBLoad の書き方もそれぞれ。 C# のそれもまた違うでしょう。 要は、アイデアを提示したということ。 「前処理と本処理の2段構えだと、いかようにも本処理を最適化しやすいのでは?」という提案です。

noname#140971
noname#140971
回答No.7

C言語で書いたのは Sony の News が発売された頃。 ですから、そのソースはないです。 ただ、Windows 3.1 の頃に書いたのは残っています。 /*--------------------------------------------------------- * bsave *---------------------------------------------------------*/ #include <stdio.h> FILE *file_open(char *, char *,char *); size_t bsave(fname, vp, recsize, dir) char *fname; void *vp; size_t recsize; char *dir; {   FILE *fp;   if (fp = file_open(fname, "wb", dir)) {     recsize = fwrite(vp, recsize, 1, fp);     fclose(fp);   } else     ferr("bsave: セーブエラー", fname, 1);   return(recsize); } bload は、全く、この逆なので割愛します。 /*------------------------------------------------------------ * t_load *------------------------------------------------------------*/ #include <string.h> #include <memory.h> typedef struct{   char member1[21];   char member2[21]; } TEST1; typedef struct{   char member1[21];   char member2[21]; } TEST2; size_t bsave(char *, void *, size_t. char *); size_t bload(char *, void *, size_t. char *); main() {   TEST1 T1;   TEST2 T2;   memset(T1.member1, 0, 21);   ・・・・   struct(T1.member1, "T1.member1");   ・・・・   bsave("test1.bin", &T1, sizeof(T1), "TMP");   ・・・・   lset(T1.member1, "");   ・・・・   bload("test.bin", &T1, sizeof(T1), "TMP");   ・・・・   putf("&---+----1----+----&0", T1.member1);   ・・・・   return(0) } [実行結果] T1.member1 T1.member2 総称的なポインタを使って、BASICのBLOADとBSAVEを再現。(昔は、かかる関数があった) 内容的には、update_bfile関数を書き込みと検索に分け、レコード1とのアクセスに限定。 30MZという当時のボロパソコンでもRAMディスクですと0.11秒でセーブとロードできたとあります。 なお、lset、putf などは自作ライブラリかも知れません。 とにもかくにも10数年前の話しです。

回答No.6

#2です。 ごめんなさい。 ArrayListだと部分一致が難しいを忘れてました。 で、話が戻る形になるのですが、以下のコードでやってみても無理ですかね。 string[] data = { "aaaa", "bbbaaa", "ababab", "asdfaa", ";lkja" }; foreach (string str in Array.FindAll(data, delegate(string s) {return s.IndexOf("aaa") != -1;})) { Console.WriteLine(str); } 多分、該当する列を取得できると思うのですが・・・ だめだったら、格納先をDataTableにしてSelectメソッドで拾ってくるしか考え付きません。 DataTableのSelectメソッド使用のサンプル※MSDN http://msdn2.microsoft.com/ja-jp/library/det4aw50(VS.80).aspx ごめんなさい。

回答No.5

#2です。 説明ありがとうございます。 状況はわかりました。 (1)は他でも使用するので今回は別として考えてます。 (4)の検索が早くなれば問題ないということですね。 (3)のボタンクリック処理で何をやっているかわからないので何とも言えないのが現状です。 まず、何の配列にデータを格納しているのでしょう。 String配列ですかね。 String配列の内部を検索する場合ですが、配列の数分の文字列を1行1行LOOPして探さなければいけません。 そんなことをしていたら時間が掛かるのは当たり前です。 なので、格納する配列をString配列からArrayListに変更してみてはどうでしょう。 予想ではかなりの時間短縮になると思います。 ArrayList内の検索を行う(中段辺りに記述) http://dobon.net/vb/dotnet/programing/icomparer.html どうですかね・・・^^;

kourogi_07
質問者

お礼

おっしゃる通り、使っているのはString配列です。やっぱり時間がかかる要因はここだったんですかね。早速ArrayListに移行してみようと思います。

kourogi_07
質問者

補足

ArrayListを導入してみました。都合上、(文字列の)部分検索を行いたいんですが、行えるような情報がありません…やはり不可能なんでしょうか。

noname#140971
noname#140971
回答No.3

BLoad、BSave なんて便利な関数はないですから自作することになります。 これは、いわゆる バイナリロード、バイナリセーブから命名したものです。 CとVBとで作った経験があります。 現在は、Access で同様のことをしています。 ' -------------------------------------------------------------------------------- ' 構造体変数 MyMenu を Menu.ini に保存 ' -------------------------------------------------------------------------------- Private Function BSave(ByVal FileName As String, ByRef MyMenu As MENU) As Boolean On Error GoTo Err_BSave   Dim isOK    As Boolean   Dim intFreeFile As Integer      isOK = True   intFreeFile = FreeFile   Open FileName For Random As intFreeFile Len = Len(MyMenu)   Put #intFreeFile, 1, MyMenu Exit_BSave: On Error Resume Next   Close #intFreeFile   BSave = isOK   Exit Function Err_BSave:   isOK = False   Resume Exit_BSave End Function A4で10ページ近い Menu.ini を呼び込んで解析し変数に取り込むなんてことをしていたら大変です。 そこで、予め<解析し変数に取り込む>は済ませておく訳です。 この場合、検索が最も簡単・高速になるように構造体変数化します。 C#は存じませんが、Cであれば当然に出来たこと。 まあ、C#も不可能ではないと思います。 ' ----------------------------------- ' Menu.bin または Menu.ini をロード ' ----------------------------------- If FileExists("Menu.bin") Then   StopNow = Not BLoad("Menu.bin", MyMenu) End If これが、実際に取り込んでいるコード部分です。 構造体変数はこれで出来上がりますので、後は、利用するだけ。 ディスクアクセスもないので超高速になります。 以下は、解析前の Menu.ini です。 この形式を幾ら工夫しても、解析する限りでは限度があると思います。 * +----------------------> アイコンの説明文 * | +--------------> アプリケーション名 * | | +----------> アイコンの場所 * | | | +--> 詳細表示の説明文 * ---------------|-------|---|-------|------------------------ * ----+----1----+----2----+----3-- 0-0-0=Icons\Large\売上伝票.ico ' 大きいアイコンの場所 0-0-1=Icons\Small\form.ico ' 小さいアイコンの場所 0-0-2=売上伝票入力 ' アイコンの説明文 0-0-3=F ' F、R、E 0-0-4=売上伝票 ' アプリケーション名 0-0-5=売上伝票フォームを開きます。 ' 詳細表示の説明文 * ------------------------------------------------------------ 0-1-0=Icons\Large\仕入伝票.ico 0-1-1=Icons\Small\form.ico 0-1-2=仕入伝票入力 0-1-3=F 0-1-4=仕入伝票 0-1-5=仕入伝票フォームを開きます。 * ============================================================ 1=月次処理(&M) ' 最大16桁 * ============================================================ * +----------------------> アイコンの説明文 * | +--------------> アプリケーション名 * | | +----------> アイコンの場所 * | | | +--> 詳細表示の説明文 * ---------------|-------|---|-------|------------------------ * ----+----1----+----2----+----3-- 1-0-0=Icons\Large\売上伝票.ico ' 大きいアイコンの場所 1-0-1=Icons\Small\form.ico ' 小さいアイコンの場所 1-0-2=売上伝票入力 ' アイコンの説明文 1-0-3=F ' F、R、E 1-0-4=売上伝票 ' アプリケーション名 1-0-5=売上伝票フォームを開きます。 ' 詳細表示の説明文 * ------------------------------------------------------------ 1-1-0=Icons\Large\仕入伝票.ico 1-1-1=Icons\Small\form.ico 1-1-2=仕入伝票入力 1-1-3=F 1-1-4=仕入伝票 1-1-5=仕入伝票フォームを開きます。 END

kourogi_07
質問者

お礼

申し訳ないんですが、VBの知識がほとんど無いのでちょっと読みづらいと言うのが正直なところです。 大変厚かましいお願いなんですが、もし可能ならばCで記述したコードを見せて頂けないでしょうか?

回答No.2

考え方が変わってしまうのですが・・・ (1)を一番最初に行う理由は? もし、無いのであれば、テキストデータを読み込みながら対象文字列がその1行に存在するか確認するロジックの方が良いと思うのですが。 (2)をやって(3)を押してから(1)と(4)を一緒に実行。 現在のままだとボタンをクリックされなくてもテキストデータを配列に格納しているから無駄かなと・・・^^; 1行ずつテキストデータを読み込むサンプル(真ん中辺りから・・・) http://dobon.net/vb/dotnet/file/readfile.html 文字列内に対象文字列が存在するか検索する方法 http://jeanne.wankuma.com/tips/string/indexof.html まぁ、VBプログラマーの言うことなので間違っているかもしれませんけど。

kourogi_07
質問者

お礼

ご返答有難う御座います。 (1)を最初に行う理由は、ボタンクリックイベントでのHDへのアクセスを短縮するためです。そして、全てのデータを読み込む理由は別にあります(説明が不足してましたね)。 このプログラムは、データをグラフにプロットして可視化することで、データの特性を見るプログラムで、一旦実行すると何度もプロットを繰り返すことになるんです。ですから、プロットの度に探索を繰り返すよりも、予め全データを読み込んでおいた方が効率的だと考えたんです。ですから(3)(4)が速ければ、(1)にどれだけ時間が掛かっても構わないんです。 説明不足ですみませんでした。

noname#140971
noname#140971
回答No.1

>予めテキストデータを全て行単位で配列に格納しておく・・・ これが許されるのならば・・・。 一介の服飾デザイナでプログラマではありません。 が、昨今は、デザイナでもCADも操作しなきゃならないしフロントエンドも開発しなきゃ務まりません。 さて、注文データとCAD内のデータを付き合わせるには実に多くの比較計算が必要。 そのようなデータをオラクルやSQL Serverに登録していたら滅茶苦茶に時間がかかります。 C言語で組んでも1オーダ90秒が限界。 しかし、たった一つの構造体変数で1レコードで記録しておけば BLoad、BSave 関数を使えば一発。 処理過程でのディスクアクセスはゼロに抑えることができます。 この場合、90秒という計算時間は0.01秒以内に短縮することが出来ました。 ある程度のサイズのデータベースも構造体変数にすることも可。 まあ、素人の考えです。

kourogi_07
質問者

お礼

ご返答有難う御座います。 構造体に全てのレコードデータを入れるということですか? また、BLoad、BSave関数という名前は初めて聞くのでよく分からないのですが、言語は何でしょうか? こっちも素人なんで…よろしくお願いします。

関連するQ&A

専門家に質問してみよう