programing」カテゴリーアーカイブ

4Dのマルチスレッドを使って処理時間を短縮する

テーブルに1万件を超えるHTMLファイルがあって、それらの中から所定のタグを抽出して別のテーブルに保存する、ような課題がありました。インタープリタモードでXeonプロセッサでも2時間以上かかっていました。同時にマルチタスクで実行すれば、使っているXeonが4コアなので1/4の処理時間、つまり30分で終わるようになるはずです。
4D Serverのモニタ画面で見ていると、CPUは25%くらいしか使われていません。4Dプロセスはインタープリターモードでは1つのコアしか使わないのです。コンパイルしてプリエンプティブ(Preemptive)モードで実行すると、「プロセス管理はシステムへと委任され、マルチコアのマシンではシステムはプロセスをそれぞれのCPUへと個別に割り当てる」とされています。
http://doc.4d.com/4Dv16/4D/16.3/Preemptive-4D-processes.300-3651705.ja.html#2821655
果たしてCPUは100%使われるのでしょうか。やってみましょう。
プリエンプティブマルチスレッドで実行するためには3つの敷居があります。マルチプロセス、プリエンプティブ、コンパイルの3つです。マルチプロセスで動くように記述されたメソッドを、スレッドセーフ(プリエンプティブモード)で、コンパイルして実行する必要があります。3つの敷居を乗り越えるように元のソースを修正するには少々手間がかかります。コンパイルするだけで早くなるかもと、次の順に試していきました。

■ コンパイル

1.【デザイン】→【コンパイル開始】
2.【実行】→【コンパイル済み再起動】
これだけです。20%ほど速くなります。ただメニューを実行するだけですので簡単です。しかしメソッドやフォームを編集しているときは【インタープリタで再起動】しなくてはなりません。特に4D Serverで複数の開発者が編集中の場合は恩恵をうけることができません。そこで問題の処理をコンポーネント化することにしました。遅い処理をコンポーネントに記述してコンポーネントだけをコンパイルしておき、ホストプロジェクトは編集可能なインタープリターで運用する、という作戦です。
コンポーネント化に伴う親テーブルをポインタ参照

 

■ マルチプロセス(マルチスレッド)

手始めにプリエンプティブではなく、コオペラティブ(Cooperative)プロセスで、マルチスレッドを実行してみました。検討した4Dコマンドは、New ProcessとCall Workerです。New processは以前からあって使ったことがあります。Call Workerはv15から使えるようになったコマンドです。今回はCall Workerを試してみます。 Call Workerの使用例

プリエンプティブでなくてもマルチプロセス化するだけで20%ほど速くなります。おそらくデータベースをクエリしたり保存したりするときに、ハードディスクのファイルI/OなどでCPUに待ち時間が発生していると考えられます。

 

■ プリエンプティブマルチスレッド

スレッドセーフという敷居があります。プリエンプティブマルチスレッドで実行するためには対象部分のメソッドがスレッドセーフでコンパイルされている必要があります。ここでは明示的にメソッドプロパティで「プリエンプティブプロセスで実行可能」をチェックします。呼び出しているメソッドすべてにこの設定をします。この設定をしておくと、メソッド内部でスレッドアンセーフなコマンドを呼び出しているとコンパイルエラーになって便利です。4Dコマンドにもスレッドアンセーフなコマンドがあります。【コンパイル開始】するとスレッドセーフなメソッドができます。
http://doc.4d.com/4Dv16/4D/16.3/Preemptive-4D-processes.300-3651705.ja.html#2821655

■ 実行結果
MacBookPro(2016)、macOS Sierraで試しました。Core i7の2コアで、4スレッド使えるようです。アクティビティモニタでCPU使用率を確認すると、コオペラティブモードでは97%くらいでしたが、これが390%とか400%近い数値になります。これでプリエンプティブになっていることがわかります。速度は4倍より遅いと感じましたが、元のよりも十分に速いです。
WindowsはOSがWindow 7で32 bitのため、プリエンプティブにしても恩恵が無いにもかかわらず、コンパイルとマルチプロセス化でかなり速くなりました。

リストボックスのイベントハンドリング(4D v16)

よくあるフォーム&ディテールの画面

エディットフィールドがいくつかあって、同じフォームに明細データがリストボックスで表示されているパターンです。

タブキーを押してフィールドを移動していき、リストボックスにフォーカスが移動したとき、このリストボックスは、
・配列型
・リストで編集可能
にしておきます。
そこで次のようにしたいです。
・配列要素がなければ1つだけ作る
・最初のフィールドに移動
これにはリストボックスのフォームメソッドに次のように記述します。

: (Form event=On Getting Focus)

If (Focus object=Self)

EDIT ITEM(vA05_lstJO_D_CODE;1) // 20170306 ok

End if

フォーカスが来たときに、EDIT ITEMを実行して、一つ目の編集可能な列に移動させています。if(focus object=self)が重要で、これがないと最初の列から次の列にフォーカスを移動できなくなってしまいます。次の列に移ろうとするときも、Getting Focusがリストボックスに対して発生してしまうからです。

VectorScript用のエディタ紹介「Visual Studio Code」

VectorScript用のエディタ紹介です。VectorScriptの文法(Pascal文法)でカラーシンタックスしてくれます。

https://www.microsoft.com/ja-jp/dev/products/code-vs.aspx

Marketplaceで、pascal対応のフリーのextensionを見つけました。

https://marketplace.visualstudio.com/items?itemName=alefragnani.pascal

インストール方法:Visual Studio Code(以下、VS Code)を起動。⌘+Pをタイプして、「 ext install pascal」をペーストしてenterキーを押す。これだけでPascal文法に対応してくれます。

Installation
Launch VS Code Quick Open (⌘+P), paste the following command, and press enter.
 ext install pascal

これでVectorScriptを編集してみると...wonderfull!!!

vscode_vectorscript
インテリセンスも働きます。次々に先行補完がされて、コーディングミスが少なくなります。
注意:ファイルパスの区切り文字が「¥」で保存されていてもutf-8で表示されると「\」になって、このまま保存するとパスが成立しなくなることがあるので注意。上記の例だとデスクトップのパスが心配ですね。スラッシュになってるし。