- PR -

VB.VETで、処理速度を早くしたいのですが

投稿者投稿内容
未記入
会議室デビュー日: 2003/02/21
投稿数: 10
投稿日時: 2003-12-23 12:48
引用:

for i=1 to 100
for j = 1 to 12
a(i,j)=a(i,j)+b(1,j)*c(i,J)
next
next



ほんとにこのループが原因ですか?
たかだか1200程度のループで?
くまのぷーさん
常連さん
会議室デビュー日: 2003/12/18
投稿数: 34
投稿日時: 2004-02-17 11:22
大昔、自分で質問を投げ、その後いろいろ試してみたので報告させていただきます。

引用:
--------------------------------------------------------------------------------
for i=1 to 100
for j = 1 to 12
a(i,j)=a(i,j)+b(1,j)*c(i,J)
next
next

というループで、このaという変数は100くらいあります。
処理速度を上げる方法、または、このようなプログラムを効率的にする方法、
参考書などをご存知の方はお教えいただけないでしょうか。

--------------------------------------------------------------------------------

というものだったのですが、2次元を1次元にすると、1.5倍くらい早くなりました。
30時間かかっていた処理を20時間で出来るようになったのはかなりうれしいです。

コードの可読性、汎用性を保てるのであれば、1次元化というのは有効であると思います。

ところで、追加の質問なのですが、配列の変数が200くらいあり(a1-a200)、その初期化を早くしたいのですが、

@redim a1(100)
ASystem.Array.Clear(a1, 0, IniPeriod)
では大差がありません。他に早い方法があれば教えてください。


はにまる
ぬし
会議室デビュー日: 2003/12/19
投稿数: 969
お住まい・勤務地: 誤字脱字の国
投稿日時: 2004-02-17 11:46
はにまるです。
引用:

くまのぷーさんさんより:
30時間かかっていた処理を20時間で出来るようになったのはかなりうれしいです。


大半の人は、その時間とループ回数から判断して
「アプローチの仕方」、「問題の特定」に疑問を持っていると思います。

パフォーマンスチューニングは、
 1.目標値と対応期限を決める。
 2.ボトルネックを探す。
 3.ボトルネックを解消する。
 4.測定し目標値以下ならば2に戻る。
の手順を踏みます。

提示された少ない情報で、私がまず疑うのが、
 1.SqlSeverへの接続回数が多い
 2.Excelへセル単位で情報の受け渡しをしている。
 3.不要な大量データ(変数を巨大に定義している)をループさせている
 4.クライアントのメモリ不足
です。

全体処理の時間が20時間と考えて宜しいですか?
20時間の内、当初提示されたロジックでどれだけ掛かっていますか?
20時間の内、今回解決したいと考えている初期化でどれだけ時間が掛かっていますか?
iStation
大ベテラン
会議室デビュー日: 2003/12/08
投稿数: 158
投稿日時: 2004-02-17 12:15
引用:

くまのぷーさんさんの書き込み (2004-02-17 11:22) より:
...
というものだったのですが、2次元を1次元にすると、1.5倍くらい早くなりました。
30時間かかっていた処理を20時間で出来るようになったのはかなりうれしいです。
...
@redim a1(100)
ASystem.Array.Clear(a1, 0, IniPeriod)
では大差がありません。他に早い方法があれば教えてください。


アンマネージドですが、C/C++でDLLを作って呼び出す手もありますよ。
更にスピードアップできると思います!
2次元用コードですが、参考にどうぞ...

// Matrix.cpp

#include <stdio.h>

extern "C" _declspec(dllexport) int _stdcall CalcMatrix(double* A, double* B, double* C, long imax, long jmax);
extern "C" _declspec(dllexport) int _stdcall ClearMatrix(double* A, long imax, long jmax);


extern "C" _declspec(dllexport) int _stdcall CalcMatrix(double* A, double* B, double* C, long imax, long jmax)
{
int i,j;

for (i=0;i<=imax;i++){
for (j=0;j<=jmax;j++){
A[i+j*(imax+1)] = A[i+j*(imax+1)] + B[i+j*(imax+1)] + C[i+j*(imax+1)];
}
}
return -1;
}

extern "C" _declspec(dllexport) int _stdcall ClearMatrix(double* A, long imax, long jmax)
{
int i,j;

for (i=0;i<=imax;i++){
for (j=0;j<=jmax;j++){
A[i+j*(imax+1)] = 0.0;
}
}
return -1;
}

' file : ArrayAddSpeed.vb
' conpile: vbc ArrayAddSpeed.vb
Imports System
Imports System.Runtime.InteropServices

Class Matrix

<DllImport("Matrix.DLL", EntryPoint:="_CalcMatrix@20")> _
Public Shared Function _
CalcMatrix(ByRef A As Double, ByRef B As Double, ByRef C As Double, ByVal imax As Integer, ByVal jmax As Integer) As Integer
End Function

<DllImport("Matrix.DLL", EntryPoint:="_ClearMatrix@12")> _
Public Shared Function _
ClearMatrix(ByRef A As Double, ByVal imax As Integer, ByVal jmax As Integer) As Integer
End Function

End Class

module Astart
sub main()
While true 'To stop: Ctrl+C

StartTime = DateTime.Now.ToOADate
Matrix.ClearMatrix(A(0,0),99, 99)
Matrix.ClearMatrix(B(0,0),99, 99)
Matrix.ClearMatrix(C(0,0),99, 99)
for k=0 to 999
i = Matrix.CalcMatrix(A(0,0), B(0,0), C(0,0), 99, 99)
next k
EndTime = DateTime.Now.ToOADate
SpanCalc = EndTime - StartTime
Console.WriteLine("Start:{0}, End:{1}, Span:{2}", StartTime, EndTime, SpanCalc)
End While
end sub

Dim A(100,100) As Double
Dim B(100,100) As Double
Dim C(100,100) As Double
Dim i,j,k As Integer
Dim StartTime As Double
Dim EndTime As Double
Dim SpanCalc As Double

end module

[ メッセージ編集済み 編集者: iStation 編集日時 2004-02-17 12:24 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-02-17 12:22
補足:
引用:

はにまるさんの書き込み (2004-02-17 11:46) より:

 2.ボトルネックを探す。


 プロファイラを使えばいいのですが、高いので、簡単に自分で実装する方法。

dim st as datetime = datetime.now
処理
dim delta as timespan = datetime.now.subtract(st)
debug.write(delta)

 処理前に“今”の時間を蓄えておき、処理後に“今”との差を取ります。こうして、「処理」にかかった時間を計測します。
 こういうのを、“時間がかかる”と思われる処理の前後に追加していきます。全ての処理で「かかった時間」を計り、一番時間がかかっているところを探します。

 たかだか1200程度の、変数へ放り込む処理で10時間も変わるとは思えません(その上でさらにループがあれば別ですが)。また、30時間が20時間になっても、私はちっとも嬉しくありません。「今日」のうちに処理が終わらないからです。または、処理するために1日中働かせてないといけないから。
くまのぷーさん
常連さん
会議室デビュー日: 2003/12/18
投稿数: 34
投稿日時: 2004-02-17 12:30
はにまるさん。
システム開発に関しては、ほとんど素人なので、以下の回答が質問への的確な回答になっているかわからないのですが・・・

引用:
--------------------------------------------------------------------------------
全体処理の時間が20時間と考えて宜しいですか?
20時間の内、当初提示されたロジックでどれだけ掛かっていますか?
20時間の内、今回解決したいと考えている初期化でどれだけ時間が掛かっていますか?
--------------------------------------------------------------------------------

20時間というのは、元データ300万件に対しての全体の処理の時間です。
処理時間は元データ数にほぼ比例していて、目標は2,000万件を100時間なので、300万件では15時間です。

当初は、他にも遅くなる要因(配列に無駄な領域が多かった)があり、40時間くらいかかっていました。

今回解決したい初期化部分は、全体の20%くらいなので、20時間中4時間という感じです。

引用:
--------------------------------------------------------------------------------
提示された少ない情報で、私がまず疑うのが、
 1.SqlSeverへの接続回数が多い
 2.Excelへセル単位で情報の受け渡しをしている。
 3.不要な大量データ(変数を巨大に定義している)をループさせている
 4.クライアントのメモリ不足
です。
--------------------------------------------------------------------------------
1.2.はRunTime上問題が無い程度です。
4はCPUがPentium4の3G、RAMは2Gです。

ご指摘のとおり、問題は3で、確かに大量データを扱っているのですが、不要な部分は出来る限り削除してはいるのですが、出力項目の多さから、なかなか減らすことは難しい状況です。

こんな負荷の大きい作業をVB.NETでやるのが問題だ、といわれればそれまでなのですが・・・







ぢゃん♪
大ベテラン
会議室デビュー日: 2003/06/12
投稿数: 208
お住まい・勤務地: 都内
投稿日時: 2004-02-17 12:45
引用:

くまのぷーさんさんの書き込み (2004-02-17 12:30) より:

20時間というのは、元データ300万件に対しての全体の処理の時間です。


その元データを読み込む部分だけで、どれぐらい時間がかかっていますか?
そこにチューニングの余地は無いですか?
はにまる
ぬし
会議室デビュー日: 2003/12/19
投稿数: 969
お住まい・勤務地: 誤字脱字の国
投稿日時: 2004-02-17 12:50
はにまるです。

 jittaさんへ> 補足ありがとうございます。
 #VB.net と SqlServer を知らないので助かります。 ^^

引用:

for i=1 to 100
for j = 1 to 12
a(i,j)=a(i,j)+b(1,j)*c(i,J)
next
next


↑これ、集計処理と思っています。
集計元の情報を取得してから、クライアントで集計をしていませんか?

変数領域が多いきい理由は、
集計の元情報自体をクライアントに格納しているからだと
勝手に想像しています。

この集計処理をSqlSever に任せる事により
クライアントの変数定義が画然に減ると思いますが如何でしょうか?

# ↓は、1プログラムで限界があった場合の次の手段と考えて下さい。

また、集計が長時間かかる処理に対して良くとる手段は、
集計プログラムを別途作成し、元テーブル→集計テーブル
集計テーブルからテキストやEXCEL出力を行う方法と取ります。


[ メッセージ編集済み 編集者: はにまる 編集日時 2004-02-17 12:55 ]

スキルアップ/キャリアアップ(JOB@IT)