:2020-03-27クラスとイベントとマルチプロセス並列処理エクセルVBAではマルチスレッドによる並列処理はサポートされていません、つまり通常は順序良く直列に処理していくしかありません。処理時間が多大にかかるような処理も現実には存在しているため、エクセルVBAで並列処理したいという要望も出てきます。マルチプロセス」これらで検索するとVBAからVBScriptを起動して時間のかかる処理を行い、その結果をエクセルで取得するというようなものが多くヒットします。そこに以下のブログが登場しました。Excelブック単体でExcelVBAを疑似マルチスレッド化してみる※運営者さんはTwitterで知っていたのでプログ掲載を直ぐに知りました。VBAでは自身のアプリケーション内ではなく、別アプリケーション(別プロセス)でExcelを起動させてブックを開くことができます。これはOLEオートメーションと呼ばれていますが、複数のプロセスを起動できるのでマルチプロセスと言って良いものになります。マルチプロセス自体はVBAとしてサポートされていると言えるのです。別のプロセスとして起動しても常に連携されているため、別プロセスのエクセルに対して何らかの命令を行ったときは処理待ちとなってしまいます。そのままではマルチスレッドのような並列処理はできないということです。上記のブログでは、この問題を解決するため、Application.OnTimeを使うことで別起動したエクセルを切り離してしまおうという発想しています。VBAをある程度やっている人なら、知っている人も多いでしょうが、Application.OnTimeはタイマー起動されるため、今動いているVBAとは全く別に動き出します。(ただし同時に並列動作はしません、実行中があればその後に実行されます。)しかしその起動自体は、元のOnTime実行したプロシージャーとは切り離されて実行予約されます。これを並列処理(マルチスレッド化)に利用しようというのが他にはない新しい発想になっています。文字列としてのプロシージャー名を起動する方法(Run,OnTime)文字列変数の中にプロシージャー名が入っていて、そのプロシージャーを起動したい場合になります、実際には、そのような構造が良いとは思えませんが、知っていればプログラミングの幅が広がります。使うのは、OnTimeメソッドorRunメソッドになります。・時刻になったら音を鳴らして知らせる最後にOnTimeの動作を確認する場合は、「時刻になったら音を鳴らして知らせる」が良いでしょう。時刻になるまではExcelの作業は何の支障もなく普通に行えます。マクロも普通に実行できます。時刻が来ると、突然マクロが起動され音が鳴ります。マルチスレッド、マルチプロセス言葉の定義としては、本来これらは別のものになります。厳密に区分けすることなくどちらでも使われている場合が多いと思います。本記事では、マルチプロセスと言ったほうがより正しいかなと思い、タイトルはマルチスレッドではなくマルチプロセスとしています。先のブログの「疑似マルチスレッド化」という表現は、非常に内容をうまく表現していると思います。先に言っておきたい重要なこと先に申し上げておきますが、決してこのような方法を推奨しているわけではありません。技術的なサンプルとして方法論の一つとして紹介しているものです。技術的な興味が優先されたVBAとなっていることを先にお断りしておきます。こんな事できるかなーという試験的なVBAだとご理解ください。昨今の事情でいえばPC自体はそんなに高価なものではなくなっていますので、1台の空きPCを用意して、そこで処理すれば済んでしまう場合も多いはずです。今回掲載のVBAコードはかなり危険なものです。危険というのは、常に安定動作するかどうかと言うことです。コンピューター処理で最も注意すべきことは、その処理が正しく行われたかどうかということです。自動化されても、それが正しくなければ全く意味がないどころか害悪にしかなりません。業務のコンピューター処理では、安全確実かつ確認しやすいシステムを優先すべきだと思います。クラスとイベントとマルチプロセス並列処理の概要OnTimeを全面的に使いながら、別プロセスとの間でデータのやり取りをしようと考えたものです。VBScriptを使用したマルチプロセスでは、結果の取得は別途出力したファイルを使うことになります。それで何も問題はないのですが、せっかく単体エクセルだけで並列処理化できるのなら、その単体エクセルの中だけで全て完結させてしまおうという発想になります。全体の簡単(大雑把)な流れは以下になります。上記処理を必要な処理数分繰り返すことになります。空きが出たら順次プロセスを開始するようにしています。起動プロシージャーは先に抜ける(一旦終了する)ようにして、終了前のOnTimeで次の処理を予約しておく。プロシージャー実行中はイベントを受け取れないので、プロシージャーを抜けて未実行状態にする必要があるためです。サブ(子)側の要点としては、メインからプロシージャーが起動されたら、直ぐにOnTimeで次のプロシージャーを起動することでメインに制御を返します。OnTimeで次のプロシージャーを起動しないと、その処理が終わるまでメインが待ち状態になるためです。VBAの全コードVBAコードの個別の解説はいたしません。それでも、VBA内の随所にコメントは入れてありますので参考にしてください。TimeOverProc("プロセス間の通信が途切れました。Long'ここは格納方法が無限にあり得るので適宜変更してください。'子プロセス側の格納に合わせて取り出す必要があります。'ある程度汎用的に書いても全てを網羅することはできないので、'以下ではサンプルとして単純なものにしています。objFSO.GetFolder(strDir).FilesobjFile.DeleteNext'テスト用にわざと処理時間がかかる処理です'他への影響軽減のためと、'「別のプログラムでのOLEの操作が完了するまで待機します」」'この対策としてDoEventsを適宜(多めに)入れてください。管理しやすさを考えたら、別モジュールにした方が良さそうに思います。モジュール名は何でも構いません。Sub全体の中で、以下が使われています。・コレクション・コールバックイベントとコールバックについては、あまりやったことがない人には参考になるのではないでしょうか。コールバックについては、本来はあまり多用すべきではないと思っているのですが、さすがに、今回のような場合は代替え手段がありませんので当然使うことになります。便利な機能ではありますが、デバッグが面倒になってしまう事が多くなります。「結果」シートだけ必要になります。VBA内で「Worksheets("結果")」これで最初に指定しています。テスト実行やプロセス起動方法の設定はConstで定義しています。テスト方法に合わせて適宜変更してください。総プロセス数(AllProc)も少ない数に変更して試してください。掲載コードのままでは動作確認するには時間がかかりすぎてしまいます。30分くらいはかかるとものとお考え下さい。最大プロセス数を1にして実行すればブレークポイント等で止めたりしても大きな問題になりません。バックグラウンドのExcelが残っても、タスクマネージャーで1つ「タスクの終了」すれば済みます。実際に使用するとしたら、設計および細部の調整がかなり大変になってくるでしょう。結局お互いが資源の取り合い状態になってしまい、速度面では期待したほどの効果は得られないことになります。今回のテストケースで言えば、PC性能にもよりますがプロセス数は4個くらいまでが限界ではないでしょうか。それ以上増やしても速度効果はあまりない、というよりむしろ遅くなってしまう場合も出てくるはずです。稼働プロセス全てで重い計算を同時に行うとか、同時に同じディスクにIOに行くとか、このような場合は、当然のことながら速度効果は少なくなります。今回のテストでは重い計算を入れたので、プロセス数が多くなるとここでCPUが振り切ってしまいます。広い意味でのリソースの競合を考慮しなければ劇的な速度アップは望めないということです。少なくとも、単に並列処理したからと言ってなんでも簡単に速くなるわけではないということをご理解ください。「別のプログラムでのOLEの操作が完了するまで待機します」このメッセージが出てしまいます。この応答で一旦停止してしまう為、本マクロは正しく処理を続行できません。従ってそのような状況にならないように適宜DoEventsを入れる必要があります。これについての確実な対策はほぼ無いと認識しています。DoEventsで解決しない場合は余計なアプリは停止する等の対策も必要になるかもしれません。場合は適宜DoEventsを入れることで対応できる場合が多いはずです。今回の試みでは、VBAコードを書くことの大変さもありましたが何より実行テストに苦労しました。処理時間がかかるものでテストしなければ検証にならないのですが、そんなに時間のかかるものを、そうそう何回も実行していられないということです。1時間かかる実行を、ただじっと見ていられるわけがありません。別の作業をしながら、「あっエラーが出た・・・」そして今やっている作業を終えてからソース確認して修正してまたテスト実行。1日に何回もテストできるものではありません。よってはエラーや正しくない結果が出ることが十分にありえることはご承知おきください。Excel2019(64bit)作成過程のテストでは総プロセス数20くらいまでは実行テストしてみました。本件についてのバグ指摘や改善提案は、ヘッダーメニューの「お問い合わせ」より頂ければ幸いです。ここに掲載しているVBAについては実験・検証とお考え下さい。実務で使う為には細部の作りこみをしっかりやる必要があります。細部を作りこむには多大な労力が必要となるでしょう。何よりデバッグが困難です、OnTimeとイベントの組み合わせなので、ステップインでのデバッグは普通にはできないものとお考え下さい。Next)|VBA入門5.ひらがな⇔カタカナの変換|エクセル基本操作6.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門7.マクロって何?VBAって何?|VBA入門8.Excelショートカットキー一覧|Excelリファレンス9.並べ替え(Sort)|VBA入門10.エクセルVBAでのシート指定方法|VBA技術解説ホームマクロVBA応用編VBAクラス入門クラスとイベントとマルチプロセス並列処理このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。アクセスランキングサイトマップ事業案内お問い合わせホームマクロVBA応用編VBAクラス入門クラスとイベントとマルチプロセス並列処理このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。