tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル 蛇足情報
投稿日: 2010/07/09(Fri) 13:06
投稿者魔界の仮面弁士
> ★2:プロパティの取得回数は最低限にしましょう★
今回はシートを例に取りましたが、他のオブジェクトであっても同様です。

たとえば、先のコードでいえば
>> xlSheet.Cells(29, xlApp.ActiveSheet.Columns.Count).End(xlToLeft).Offset(3, 0) = Average
なども、できれば見直しておいた方が良いでしょう。

VB6 から Excel を操作する場合、別のプロセスに対する操作を行うことになるため、
その操作はやや低速なものとなってしまいます。

そのため一般的には、
 ・「1 行挿入」を X 回繰り返す。
よりも
 ・「X 行挿入」を 1 回行う。
方が、Excel との通信回数が減る分、処理効率が良くなります。


たとえば下記のようにして、1000 個のデータを書き込んでみた場合、
当方では平均 3.0 秒という時間を要しました。
ユーザーにとってみれば、秒単位の待ち時間というのは比較的低速な処理であり、
実行すると、Excel のスクロールバーがだんだんと延びていく様子が見えます。

    Dim t As Single
    t = Timer

    Dim row As Integer
    For row = 1 To 500
        'Value プロパティへの代入操作が、計 1000 回行われている。
        xlSheet.Cells(row, 1).Value = 10000 + row
        xlSheet.Cells(row, 2).Value = 20000 + row
    Next

    Debug.Print "処理時間:"; Timer - t


上記の「xlSheet.Cells(row, 1).Value = 10000 + row」というコードでは、
Cells プロパティを利用しているわけですが、実は Cells プロパティというのは
「引数の無いプロパティ」なのです。一見、引数が指定されているように見えますが、実は
「xlSheet.Cells.Item(row, 1).Value = 10000 + row」という操作が行われています。

※ 正確には .Item ではなく .[_Default]


すなわち「xlSheet.Cells(row, 1).Value」というコードでは、

 (1) Worksheet オブジェクトの Cells プロパティから、
  シート内の全てのセルを表す巨大な Range オブジェクトを得る。

 (2) Range オブジェクトの既定のプロパティから、row 行目 1列目のセルを
  単一セルを表す Range オブジェクトを得る。

 (3) Range オブジェクトの Value プロパティにデータを割り当てる。

という手順が発生しており、それを都合 1000 回繰り返していたというわけです。


この場合、オブジェクトの操作方法を工夫することで処理速度が向上します。
先のコードでは、3.0 秒でしたが、下記のコードだと 1.5 秒にまで半減しました。

    Dim t As Single
    t = Timer

    Set xlRange = xlSheet.Range("A1:B1")   '基準位置となる 2セル分だけ取得

    Dim row As Integer
    For row = 1 To 500
        '2 セルずつ操作する事で、Value への書き込み回数を半分に減らす。
        xlRange.Value = Array(10000 + row, 20000 + row)  '1 次元配列を渡す
        Set xlRange = xlRange.Offset(1)                  '下に1行ずらす
    Next

    Debug.Print "処理時間:"; Timer - t


さらに手を加えて、Value への書き込みを 1 回だけにしてやれば、
ほぼ一瞬(0.1 秒未満)で処理を完了させることもできます。

    Dim t As Single
    t = Timer

    Set xlRange = xlSheet.Range("A1:B500")

    Dim data() As Variant
    data = xlRange.Value   '500行×2列 の 2次元配列を得る。

    Dim row As Integer
    For row = 1 To 500
        'ローカル配列への代入なので、この処理は非常に高速に行われる。
        data(row, 1) = 10000 + row
        data(row, 2) = 10000 + row
    Next

    'Value プロパティへの代入操作は、この 1 回だけで済む。
    xlRange.Value = data

    Debug.Print "処理時間:"; Timer - t


なお無駄なオブジェクト操作は、速度低下を招くだけでなく、環境によっては
ハングアップの要因となる可能性もありますのでご注意ください。
http://support.microsoft.com/kb/414107/ja
(とはいえ、最近の環境であればハングアップまではしないと思いますが)

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。