和風スパゲティのレシピ

日本語でコーディングするExcelVBA

マクロの速度は追求すべきものだけを追求すべし

マクロの高速化に関する考察です。


「マクロの処理速度はどこまで気にするべきか」
というテーマです。


プログラミングに限らず、訓練とか練習って

  1. 最初は量をこなすので精一杯
  2. だんだん慣れてきて、質にこだわれるようになる
  3. 今度は質を気にしすぎて、量がこなせなくなる
  4. 量と質のバランスが取れるようになる

という成長を遂げる気がします。

この3で感じるスランプ感から、
4へ抜け出す手助けになればいいなと思って書いていきますね。

注:ある程度の基本はおさえた前提の話です


最初に注意事項です。

Application.ScreenUpdating = False

で画面の描画を止めるとか、

Range("A1").Select
Selection = ○○

↑このSelectをやめるとかは、高速化ではなく基礎です。


今回題材にしてるのは、

  • このループ処理は参照が重複しちゃってるな~
  • Ifの組み方が無駄な判定をしてそうだな~
  • 違うメソッドを使った方が早いのかな~

などの、ロジック的なお話です。


「Selectしない」っていうのは、

  1. 最初は量をこなすので精一杯
  2. だんだん慣れてきて、質にこだわれるようになる
  3. 今度は質を気にしすぎて、量がこなせなくなる
  4. 量と質のバランスが取れるようになる

↑この話でいうところの「1から2の話」です。
速度を追及されない場面でも、Selectはしてはいけません。


まだ1の段階の方は、何でもかんでも高速化して、経験を積んだ方がいいです。
量をこなしていないのに、「効率よく高速化」なんてできませんからね。

1⇒2の訓練をサボる口実に、この記事を利用しませんように。
この記事の対象者は、3の方ですよ。


と保険をかけてから、本文に入ります。

マクロの速度には限界が(キリが)ない

まず大前提として、マクロを「理論上最速」にするのは不可能です。

ただのコードの精査ですら、高速にしようと思ったらいくらでも高速になりますし、
Excelを2つ立ち上げてマルチコアで処理みたいな、
とんでもマクロを見たこともあります。(私は作れません)


ひとまず、最速を目指すことは不可能なので、

「どうやって早くするか」よりも、「どこまで早くするか」を先に考えることが大事

というのをまずは意識しましょう。

まず一番は「なんのために」

どこまで早くするか を考えるには、
まず「どうして早くするのか」を考えましょう。


「そんなもん早くした方がいいからにきまってるだろ!」


と言わないでください。
例えば↓の高速化が出来そうだとします。

  • A:4時間 ⇒ 2時間
  • B:10分 ⇒ 5分
  • C:2秒 ⇒ 1秒

どれをやるべきでしょうか?


これだけだとまだイメージしづらいですね。

もっと詳しく書くと、

  • A:月1回の業務。実行して帰宅して、次の日の朝終わっていればいいマクロ
  • B:毎週月曜日の朝に実行しなければいけないマクロ
  • C:ツールバーにボタンを登録していて、ポチポチ使える汎用マクロ

こうだとします。


これで答えは出ましたね。

まっさきにCをやりましょう。

ツールバーのマクロが早いと快適で、仕事が捗ります。
逆にポチポチ押せるボタンの反応が悪いと、ストレスマッハですからね。

この1秒は重要な1秒です。


次いでBですが、まあやる必要が生じたらやりましょう。

休み明けの10分なんて、給湯室にいる間に過ぎ去りますし、
週初めのミーティングとかあるならその裏で実行すればいいです。


やるかどうかをしっかり考える必要があるのがAです。
つけっぱなしのPCがお休みするまでの時間しか変わっていません。


Aのマクロに求められるのは、速度よりも絶対に止まらない頑強性です。
Aのマクロが万が一止まっても、あなたはその時お風呂にいるのです。


高速化がストレートな方法で出来るならやってもよいでしょう。
停電やPCトラブル、憎きWindowsアップデートなどの発生率を考えれば、
速度を上げることは副次的に頑強性にもつながります。


しかし、高速化が複雑な方法を必要とする場合はやめておいた方がいいでしょう。
止まってしまうリスクの方が高く、リターンと釣り合わない可能性が高そうです。


と、こんな感じでマクロにはマクロの目的があるので、
どれくらい速くするかよりも、速くなったとき何がうれしいかの方が重要です。

また、高速化には難読化も付きまとうので、
メンテがどれくらい発生するか = コードが読みやすいか
ともバランスをとる必要があります。


早くなったらうれしいかどうかを考えて、
嬉しい物だけを高速化しましょう。

次に「どこをはやくするか」

晴れて「早くした方がうれしいマクロ」は決まりました。


次にどうやって早くするかですが、その前に。


プログラムの性質として、

「すべての処理を少しずつ早くするよりも、
最も遅い処理をガッツリ早くした方が全体の処理速度は早くなる」

という性質があることは知っておきましょう。


なので、まずは「一番遅い処理がどこか」を考えなければいけません。


なんですが、その処理を見分けるには、経験がものを言います。
なかなか「遅い処理はこれ!」というのは難しいです。

Debug.Print "○○の処理まで終了:" & Time

をコード内にちりばめておけば、
おおよそどの辺が遅いかは見当がつきますので、
後はどの処理が重くなっているか、がんばって調べましょう。


ということで、「どこをはやくするか」の見極めは訓練しかないのですが、
訓練しなくてもすぐに効果が出るものがあります。


それは「どこをはやくしても意味がないか」を意識することです。

これは何となくイメージできるんじゃないでしょうか?
一瞬で終わりそうな箇所には手を入れなくていいということです。

  • Integer より Longがはやい
  • Worksheets("シート名") より Worksheets(1) がはやい
  • Range("A1")よりCells(1, 1)がはやい

あたりの、うんちく好きが語るどうでもいい部分も、片っ端から無視していいです。


この判断が出来るようになるだけでも、

「速度を気にしてキリがない」状態を脱する、
ひとつのきっかけになると思います。

最後に「どう早くするか」

いよいよ高速化です。

どうやったら早くなるかを考えましょう。


当たり前ですが、「こうやれば早くなります」なんてありませんので、頑張って考えてください。

いままでの過程を経て「早くする意味あるかな?」とか、
余計なことで気が散らない頭になっているはずです。

集中して考える土台は整っていますので、
思う存分高速化してください。

まとめ

今回は「マクロの速度は、それを追求すべき箇所でだけ追求する」ということで、

  1. まずは「なんのために早くするのか」考える
  2. 次に「どこをはやくするのか」考える
  3. 最後に「どうやって早くするのか」考える

というお話でした。


マクロの早さが気になって、キリがないよ~に陥っていた人は、
早くする意味のないマクロ
早くしても無駄な処理
を意識するようにしてみましょう。

おまけ:やりたくなるけどやってはいけない高速化

早くする意味があまりなく
難読化するデメリットが大きい高速化が↓このあたりです。

1個のFor文で、なるべく多くのことを済ませようとする

www.limecode.jp

Elseを使って、Ifが同じ判定を何度もしないようにする

www.limecode.jp


「早くする意味なし!」と直感気付きにくいので、
意外とやってしまっている方は多いかもしれません。

やっちまっていた方は、
これを機にこれらの処理を「読みやすさ重視」にシフトしましょう。