VBAでマルチスレッド処理を実現し、超高速化を実現する | システムエンジニアライフ

VBAでマルチスレッド処理を実現し、超高速化を実現する

ヘッダー広告
スポンサードリンク
今回はVBAでマルチスレッド処理を実現して、超高速化を実現する方法についてお教え致します。
マルチスレッドとは、プログラムの実行を複数同時(並列)に実行することです。
VBAではマルチスレッドは基本的には出来ないのですが、今回お伝えする方法を使用することで、仮想的にマルチスレッドが実現可能となります。

VBAでマルチスレッドを使用しなくてはいけないような状況はなかなかないと考えています。
私は最近外部サイトのAPIをVBAにて実行させて値を取得するプログラムを作成していたのですが、その際に普通にプログラムを実行すると一つ一つのAPI呼び出しにネットワーク接続を行うため、かなり時間が掛かってしまいます。
マルチスレッドを使用することで、複数のAPIを同時に呼び出すことができ、通常の処理方法と比較して超高速で処理を実行することが可能となります。

マルチスレッドによる超高速VBAの実現


普通にAPIをVBAで実行した場合の処理時間


まずVBAにて普通にAPIを実行した場合の処理時間についてご紹介致します。
ロジックは以前にVBAでXMLを操作する方法にてお伝えしたプログラムをカスタマイズして使用します。

VBAでXMLを操作する方法

プログラム
Option Explicit

Private Const PREFECTURE_START_NO As Long = 1
Private Const PREFECTURE_END_NO As Long = 47
Private Const EKIDATA_API As String = "http://www.ekidata.jp/api/p/"
Private Const EXTENSION As String = ".xml"
Private Const EKIDATA_FILENAME As String = "ekidata"

Public Sub VbaDataImport()

    Dim OutPutPath As String
    Dim i As Long
    Dim StartTime As Date
    Dim EndTime As Date
    Dim Xml As Object
    Dim CreateXml As Object
    Dim CreateNode As Object
    Dim FilePath As String
    
    StartTime = Format(Now, "hh時mm分ss秒")

    'ファイル出力用フォルダ作成
    OutPutPath = ThisWorkbook.Path & "\" & Format(Now, "YYYYMMDDhhmmss") & "\"
    MkDir OutPutPath
    
    Set Xml = CreateObject("Microsoft.XMLDOM")
    Xml.async = False
    
    For i = PREFECTURE_START_NO To PREFECTURE_END_NO
            
        FilePath = OutPutPath & EKIDATA_FILENAME & i & EXTENSION
            
        Xml.Load EKIDATA_API & i & EXTENSION
        
        If (Xml.parseError.ErrorCode <> 0) Then 'ロード失敗
            
            Set CreateXml = CreateObject("Microsoft.XMLDom")
    
            Set CreateNode = CreateXml.appendChild(CreateXml.CreateElement("status"))
    
            Set CreateNode = CreateNode.appendChild(CreateXml.createTextNode("Failure"))
            Set CreateNode = CreateNode.ParentNode
    
            CreateXml.Save FilePath
    
        Else
            Xml.Save FilePath
            
        End If
    
    Next
                
    EndTime = Format(Now, "hh時mm分ss秒")
            
    MsgBox "処理が完了しました。" & vbCrLf & _
           "開始時刻:" & StartTime & vbCrLf & _
           "終了時刻:" & EndTime & vbCrLf & _
           "かかった時刻:" & Second(EndTime - StartTime) & "秒" _
            , vbInformation, "処理完了"
            
End Sub


実行にかかった時間は以下のようになりました。


ネットワークの状況にもよりますが、たった47リクエストにもかかわらず20秒以上もかかってしまっています。
これではAPIでのデータ取得など到底出来ないです。

VBSと連携させてマルチスレッドを実現したコード


続けてVBAとVBSを連携させて、マルチスレッドにてAPIを実行した場合の処理時間についてご紹介致します。

プロシージャはAPIを実行するメインのプロシージャと、VBSを作成するプロシージャの二つとなります。

●API実行するメインプログラム
Option Explicit


Private Const PREFECTURE_START_NO As Long = 1
Private Const PREFECTURE_END_NO As Long = 47
Private Const EKIDATA_API As String = "http://www.ekidata.jp/api/p/"
Private Const EXTENSION As String = ".xml"
Private Const EKIDATA_FILENAME As String = "ekidata"
Private Const VBS_NAME As String = "getAPI.vbs"


Public Sub VbsDataImport()
    
    Dim OutPutPath As String
    Dim i As Long
    Dim StartTime As Date
    Dim EndTime As Date

    StartTime = Format(Now, "hh時mm分ss秒")

    'ファイル出力用フォルダ作成
    OutPutPath = ThisWorkbook.Path & "\" & Format(Now, "YYYYMMDDhhmmss") & "\"
    MkDir OutPutPath
        
    'xmlファイル出力用フォルダ作成
    Call MakeVBS(OutPutPath)
        
    For i = PREFECTURE_START_NO To PREFECTURE_END_NO
        
        'API処理実行
        Shell "WScript.exe " & _
                  """" & OutPutPath & VBS_NAME & """ " & _
                  """" & EKIDATA_API & i & EXTENSION & """ " & _
                  """" & OutPutPath & EKIDATA_FILENAME & "_" & i & ".xml"" "
                
    Next
                
    EndTime = Format(Now, "hh時mm分ss秒")
            
    MsgBox "処理が完了しました。" & vbCrLf & _
           "開始時刻:" & StartTime & vbCrLf & _
           "終了時刻:" & EndTime & vbCrLf & _
           "かかった時刻:" & Second(EndTime - StartTime) & "秒" _
            , vbInformation, "処理完了"
            
End Sub


●VBSを作成するプログラム
Private Sub MakeVBS(ByVal OutPutPath As String)

    Dim Fso As New FileSystemObject
    Dim VbsFile As TextStream
    
    Set VbsFile = Fso.CreateTextFile( _
                    Filename:=OutPutPath & VBS_NAME, _
                    overwrite:=True, _
                    Unicode:=False)
    
    With VbsFile
        
        .WriteLine ("    Dim FilePath")
        .WriteLine ("    Dim Xml")
        .WriteLine ("    Dim CreateXml")
        .WriteLine ("    Dim CreateNode")
        .WriteLine ("")
        .WriteLine ("    FilePath = WScript.Arguments.Item(1)")
        .WriteLine ("")
        .WriteLine ("    Set Xml = CreateObject(""Microsoft.XMLDOM"")")
        .WriteLine ("    Xml.async = False")
        .WriteLine ("    Xml.Load WScript.Arguments.Item(0)")
        .WriteLine ("")
        .WriteLine ("    If (xml.parseError.ErrorCode <> 0) Then 'ロード失敗")
        .WriteLine ("")
        .WriteLine ("        Set CreateXml = CreateObject(""Microsoft.XMLDom"")")
        .WriteLine ("")
        .WriteLine ("        Set CreateNode = CreateXml.appendChild(CreateXml.CreateElement(""status""))")
        .WriteLine ("")
        .WriteLine ("        Set CreateNode = CreateNode.appendChild(CreateXml.createTextNode(""Failure""))")
        .WriteLine ("        Set CreateNode = CreateNode.parentNode")
        .WriteLine ("")
        .WriteLine ("        CreateXml.save FilePath")
        .WriteLine ("")
        .WriteLine ("        WScript.Quit")
        .WriteLine ("")
        .WriteLine ("    End If")
        .WriteLine ("")
        .WriteLine ("    Xml.save FilePath")
        
        .Close
    End With
    
End Sub


こちらの処理で実行にかかった時間は以下のようになりました。


なんとかなり速度が改善され、たったの3秒で実行出来ました。
このようにVBAからVBSを作成し、そのVBSを実行するようにすれば、VBAでもマルチスレッドが実現でき、処理の超高速化が実現することが可能となります。

今回のサンプルプログラムでは、XMLの保存だけしていますが、そのまま処理したい場合には、wait時間を設定して、ファイルの存在確認をするコードを記載することで、xmlファイルを取得することが可能となります。

今回のプログラムの注意点


今回ご紹介したように、VBSでマルチスレッドを実現することで超高速化を実現することが可能となります。
それはかなり便利なことではありますが、同一サイトに対して短時間に大量のアクセスを行うとそのサイトに多大な負荷をかけることとなります。
呼び出すAPIの数に応じて、ループ処理の一つ一つにwait時間を設ける。アクセスの多い時間帯を避けるなど、サイトに迷惑を掛けないようにする工夫が必要となります。
APIを使用する開発者のマナーやルールとして意識して開発するようにしましょう。

今回はAPIを呼び出す処理にピックアップしてご紹介させていただきましたが、VBSとの連携は色々な処理で応用できるロジックとなります。
参考にしていただき、VBA開発者としてより高いレベルで要件を実現していきましょう!
フッター広告

スポンサードリンク



シェアする

  • このエントリーをはてなブックマークに追加

フォローする