SSブログ

エクセルのちょっといい話(20):エクセル2003の並列実行 [エクセル]

KFシステムクリエイターの管理ツールであるKFシステムコントローラには、複数のエクセルを同時に起動し、それぞれのエクセルで開いたブックのマクロを個々に実行する「並列実行ツール」が内包されています。
これは、Core i5などのマルチコアCPU環境でシステムを運用する場合に有用です。

KFシステムクリエイターは極めて複雑なシート構成となっているため、マルチコアを有効にしたエクセルで実行すると、頻繁にオーバーヘッドが発生し、処理が著しく停滞したり、場合によってはハングアップしてしまうことがあります。
そのため、システムの実行環境としては、マルチコアやマルチスレッドを解除することを推奨しています。

しかし、そうすると当然のことながら、マルチコアCPU環境であっても一つのコアしか使用することが出来ません。例えば4コアCPUの場合では、CPU使用率は最大で25%程度にしかならないわけです。
そこで、エクセルを別インスタンス(プロセス)で4つ同時に起動し、それぞれで異なる処理を行わせることで、CPUの実効使用率を100%ほどに高めることが出来るようになります。

本来であれば、エクセルの標準的な機能としてマルチタスクが実現できればいいのですが、残念ながら仕様上、シングルタスクによる逐次処理しか出来ません。
そのために、複数のブックに分かれた重い処理を並列・同時に行うためには、別インスタンスで複数のエクセルを起動し、それぞれで処理を行ってやる必要があるわけです。

それを実現するために、並列実行ツールでは、「エクセルを起動して指定ブックを開きマクロを実行させる」、という一連の操作をVBSファイルで書き起こし、それを複数同時実行させることで、"疑似的"に並列処理を実現しています。

この処理では負荷の調整や配分が出来ないため、事前に各処理に掛かる時間を見計らって、各インスタンスに出来るだけ均等になるよう実行ファイルを配分してやる必要があります。
そのため、あくまで"疑似的"な並列処理(マルチタスク)となっています。

本来のマルチタスクであれば、先に処理が終わって待ちが生じているインスタンスに対し、他のインスタンスで処理待ちのファイルがあれば、それを割り当てることが出来るはずなのですが、本並列実行ツールでは残念ながらそれは出来ません。それゆえに、"疑似的"ということになります。

しかし、KFシステムクリエイターにおいて最も処理が重い時系列分析においては、各処理に掛かる時間が長いため、基本的には処理待ちが生じる余裕はありません。
そのために、"疑似的"な並列実行ツールであっても、その効果が損なわれることはほとんどありません。

従来は、エクセルにおいて並列処理を行うためには、このようなVBSを介しての"疑似的"な方法しかありませんでした。私が最初にシステムに実装したのは2008年3月のことですから、それ以前も含めてずいぶん長い間、新たな試みはなされていなかったように思います。

しかし、最近になって(といっても2年前ですが)、VBSを介さないでマルチスレッドを実現する方法が、"ことりちゅん"さんによって提案されました。

それは、Application.OnTimeを使用するというものですが、詳細につきましてはご本人のブログをご参照ください。なお、リンクの許可申請をしておりませんので、「ことりちゅん マルチスレッド VBA」でググってみてください。
検索結果上位にある2019年3月27日の記事が、それに該当するかと思います。

さて、今回の記事で紹介したいのは、実はこの新たな方法の事ではありません。少なくともKFシステムクリエイターにおいては、従来のVBSを介した並列処理で速度的な問題はなく、使用上の不便等を感じる場面もありませんでした。

私は専らエクセル2003環境でシステム開発や実行を行ってきたのですが、少なくともその環境においては現在も全く問題はありません。
しかし、Microsoft365(旧Office365)の導入により、状況は一変しました。並列実行ツールで処理を行うと、最新エクセルが同時起動するようになったのです。

もっとも、これは随分以前から分かっていたことであり、従来はエクセル2003の自動修復を実行することにより、エクセル2003を既定アプリとして設定し直していました。
また、並列実行が効力を発揮する時系列分析では、最近まで自動実行ツールが出来ていなかったこともあり、並列実行ツールを使用することがなく、特に不便を感じることはありませんでした。

しかし、最近になってやや重い処理を並列実行ツールで行ったところ、起動したエクセルのシートがずれて重なって表示されることに気が付きました。
それが、各処理毎に生じる訳ですから、画面レイアウトはぐちゃぐちゃで訳が分からなくなり、現在どの処理を行っているのか見当が付きません。

調べてみると、これはエクセル2013以降の仕様であり、従来のMDI(マルチ ドキュメント インターフェイス)からSDI(シングル ドキュメント インターフェイス)に変更されたため、ということが分かりました。
しかも、この仕様は設定等で変更できず、ユーザー側では対処のしようが無いようです。

KFシステムクリエイターにおいては、エクセル上でブックを次々に呼び出して処理を連続して行うことが多いのですが、エクセル2003(正確にはエクセル2010以前)では、同一インスタンス上で開いたブックが全て重なって表示されていたため、表示上の問題はありませんでした。

しかし、エクセル2013以降では、せっかく各インスタンスで最初に起動するエクセルブックの位置を決めてやっても、そこから更に呼び出されるブックの表示位置までは制御できなくなってしまいました。
もちろん、各ブックのマクロに、表示位置を決める命令を書き込んでおけば良いのかもしれませんが、使用環境によっては却って面倒な事になる可能性があります。

元々、システムの実行環境としてはエクセル2003が最も適していることから、それがインストールされている環境では、強制的にエクセル2003を起動することを考えました。
具体的には、最初に並列実行ツールを起動したエクセルのバージョンが2003であれば、同ツールから起動されるエクセルもまた2003とする、と言うことです。

もちろん、エクセル2003がインストールされていない環境や、並列実行ツールを起動したエクセルのバージョンが2003以外の場合は、従来通りの処理を行うものとします。
その際、ブックがずれて表示されるという症状は解消しませんが、最終的な処理結果に影響を与えるものではありません。

一番手っ取り早いのは、前述した通りエクセル2003上でアプリケーションの自動修復を実行する、というものです。
しかし、Microsoft365を使用している場合、かなり頻繁に再修復が行われて、既定アプリが最新エクセルに変更されるという問題があります。

並列実行ツールでは、Excel.Applicationオブジェクトを生成してエクセルを起動していますが、この場合、既定のエクセルしか実行できません。
レジストリの変更でこれを回避するという方法も、ネット上には散見されますが、根幹にかかわる部分をあまり変更したくはありません。

そこで、もう一つ考えられるのが、WScript.Shellオブジェクトを用いるという方法です。これを用いて、エクセル2003を直接実行してやれば、既定に関わらず2003バージョンを開くことが出来ます。
しかし、ここで重大な問題が生じます。この方法だと、エクセルのブックを開くところまでは実行できても、それに含まれるマクロを実行することは出来ない、ということです。

Excel.Applicationを用いる従来の標準的な方法であれば、ブックのオープンやマクロの起動など、エクセルで行う様々な処理を指定することが出来るのですが、WScript.Shellでは各アプリケーションが標準的に持っている機能(引数)しか指定することが出来ません。

そこで、この問題を回避するために、最初に起動するブックに自動実行マクロを含ませることにしました。具体的には、起動専用ブックを並列実行マクロから新たに生成し、そのThisWorkbookモジュールのWorkbook_Openプロシージャに、本来起動したいブックとマクロを記述するという方法です。
合わせて、表示位置や終了処理等も記述してやれば、従来の並列実行ツールと同等の処理が出来ます。

起動したいブックの名称やマクロ名、終了処理等に必要ないくつかの指標については、起動専用ブックのシートに予め記載しておき、ブックのオープン時に参照するようにしています。
マクロを起動専用ブックに付加するには、CodeModuleオブジェクトを使用します。これを行うには、事前にVBEのツールから参照設定を開き、「Microsoft Visual Basic for Applications Extensibility 5.3」を有効にしておく必要がります。

あとは、起動専用ブックのエクセル2003からの実行をVBSファイルに書き出し、並列実行ツールからVBSを実行すれば、目的のブックが複数のエクセル2003から起動し、マクロが実行されます。
・・・となるはずでしたが、実はエクセル2003の起動時に、セキュリティ警告が出てしまうことが分かりました。Excel.Applicationを用いた方法ではこの警告は出ないのですが、WScript.Shellを用いると回避できないようです。

これは、エクセル2003のマクロのセキュリティレベルを"低い"に設定しておけば、回避することが出来ますが、常時この設定にしておくのはさすがに気が引けます。
さりとて、並列実行マクロを起動する度に、セキュリティ設定を手動で変更するのも面倒です。

そこで、やや反則的ですが、レジストリをいじることにしました。といっても、システムを不安定にさせかねない大規模なものではなく、セキュリティのレベルを変更するだけのものです。
そして、起動専用ブックが開き、VBSの処理が終了するタイミングで元に戻します。こうすることで、次回以降のエクセル2003の起動時には、セキュリティレベルは標準の"中"(KFシステムクリエイター推奨設定)に戻っていることになります。

エクセル2003のセキュリティレベル変更には、レジストリの"HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\11.0\Excel\Security\Level"の値を設定し直します。
この値が"1"ならセキュリティレベルは"低い"、"2"なら"中"となります。更に、"3"なら"高"、"4"なら"最高"となります。レジストリの書き換えには、WScript.ShellのRegWriteメソッドを用います。

これでようやく、パソコン環境に依存せずにエクセル2003を並列起動出来るようになりました。
なお、レジストリの操作には常に危険が付きまといます。また、安易にセキュリティレベルを下げる行為についても、十分な注意が必要です。

ちなみに、エクセル2003が入手できない場合など、それよりも新しいバージョンのものを使わざるを得なくても、2013以降は表示の問題で使いたくないことがあるかもしれません。
その場合は、エクセル2003の実行ファイルとレジストリの部分を、例えばエクセル2010のものに置き換えてやれば、対応可能だと思います。

nice!(0)  コメント(0) 
共通テーマ:

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

Facebook コメント

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。