2017-12-23 14 views
3

のためにVBAでシェル機能をスピードアップする方法libc.dylib:私が使用する、VBA(execShell機能)内のシェルスクリプトを実行するために、この質問には、トップの答えから関数を使用してきたマック

VBA Shell function in Office 2011 for Mac

この関数内ではwhileループであり、popenよりもはるかに遅く実行されます。私はこの部分がシェル内で実行されていて、popenが初期化されていると推測していますが、実際に何をしているのか分かりません。

Time taken to run popen: 
0.01171875 seconds 
Time taken to run while loop: 
0.8710938 seconds 

実行に時間がかかる場合は、機能を中止するかタイムアウトすることができますか?複数の関数呼び出しを処理するために使用できるメソッドはありますか?シェルスクリプトのcurlコマンドにタイムアウトを追加しました。 "curl --connect-timeout 5 --max-time 10 --retry 2 --retry-delay 0 --retry-max-time 40 "に追加され、各コールの前に0.1秒の遅延が追加されました。それがスムーズに動いた場合、それは問題ではないでしょうが、時には完全にロックアップしているように見えることがあります。カールのリクエストに長時間の遅延がある場合、私はそれを中止してスクリプトを続行することをお勧めします。おそらく、いくつかの連続した失敗がスクリプトを完全に終了させた後です。関数呼び出しは線形に処理されると思っていましたが、シェルスクリプトを同時に処理する可能性があり、これが問題の原因になる可能性があると考えています。理想的には、ステータスバーを使用して実装しようとしたスクリプトのステータスに関するフィードバックを得たいと思いますが、これは2011バージョンのExcelの制限のためには機能しませんでした。実行の開始時に、シートが更新され、すべてがスムーズに実行されていることがわかりますが、後でスクリプトが完了するまで凍結します。

もう1つの解決策は、MacScriptコマンドを使用することですが、このシェルスクリプトには "\"と複数引用符を含む正規表現が含まれています。これは、AppleScriptに変換するのが非常に難しいので、 。 system()コマンドの使用は、VBAスクリプトに出力が必要なため、オプションではありません。

Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As String) As Long 
    Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long 
    Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long, ByVal items As Long, ByVal stream As Long) As Long 
    Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long 

    Function execShell(command As String, Optional ByRef exitCode As Long) As String 
     Dim file As Long 
     file = popen(command, "r") 

     If file = 0 Then 
      Exit Function 
     End If 

     While feof(file) = 0 
      Dim chunk As String 
      Dim read As Long 
      chunk = Space(50) 
      read = fread(chunk, 1, Len(chunk) - 1, file) 
      If read > 0 Then 
       chunk = Left$(chunk, read) 
       execShell = execShell & chunk 
      End If 
     Wend 

     exitCode = pclose(file) 
    End Function 

答えて

2

popen高速に実行され、それは、C/C++で書かれたバイナリ実行可能ですので。オペレーティングシステムレベルで実行され、VBA仮想マシン(VBA VM)では実行されません。 WhileループとVBAのその他のものは、VBA VMで実行されるスクリプト言語です。スクリプト言語は、VBA VMによって実行されるpコードにスクリプトを変換する必要があります。ウィキペディアの“Visual Basic for Applications”の記事は、興味があれば詳細な説明を提供しています。

VBAコードは、Excelオブジェクトまたはpopenのような外部関数によって提供される方法よりも常に遅くなります。たとえば、Range Objects AutoFillメソッドを使用すると、範囲を値で満たすループが実行されている間は常にVBAよりも高速になります。

コードに「タイムアウト」を追加するための最良の方法は、あなたのwhileループ内のVBAメソッドDoEventsを追加することです。これは、ExcelおよびWindowsはイベントを処理できるようにするWhileループが発生します

 End If 
    VBA.DoEvents 
Wend 

:次に

私はこのようなEnd If間とWend何かにそれを置くと思います。 VBA Shell()機能を除き、VBAコードは順次実行されます。 VBA.DoEventsがなければ、コードは完了またはエラーが発生するまで実行を継続します。このStack Overflow question threadは大きな説明を提供します。

コードをスピードアップできることの1つは、このコマンドを使用して画面更新をオフにすることです。Application.ScreenUpdating = FalseApplication.ScreenUpdating = Trueでサブの最後に戻してください。あなたが本当に冒険を感じているならば、あなたはイベントハンドラを書くことができまた

Application.ScreenUpdating = False 
While feof(file) = 0 
. 
. 
. 
Wend 
Application.ScreenUpdating = True 

:私はこのようなWhileループの周りにそれを置くと思います。チップピアソンは素晴らしい記事“Events and Event Procedures in VBA”を持っています。

+0

ご回答ありがとうございます。私はDoEventsをループに追加しました。さらにデバッグした後、私の問題は、スクリプトが遅すぎるということではなく、サーバーが一定時間後に要求をブロックし、数分後にブロックが削除され、スクリプトが続行されるということです。待ち時間を0.1秒から0.5秒に変更しましたが、その部分を解決しましたが、タイムアウトするとカールのエラーを設定する必要があります。私もconnect-timeoutを5秒から変更します。これは、一部の要求では十分ではありませんが、ほとんどの場合、1秒未満です。 – Matts

関連する問題