2017-12-23 3 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 초 지연이 추가되었습니다. 그것이 원활하게 실행되면 문제가되지 않지만 때로는 완전히 잠겨 버리는 것처럼 보일 수 있습니다. 곱슬 곱슬 요청이 길게 지연되면 스크립트를 중단하고 스크립트를 계속 진행하는 것이 좋습니다. 어쩌면 몇 번 연속 실패하면 스크립트가 완전히 종료 될 수 있습니다. 함수 호출이 선형 적으로 처리 될 것이라고 생각했지만, 쉘 스크립트를 동시에 처리 할 수 ​​있다고 생각합니다. 문제가 발생할 수 있습니다. 이상 적으로는 상태 표시 줄을 사용하여 구현하려고 시도한 스크립트의 상태에 대한 의견을 보내고 싶지만 Excel 2011 버전의 제한으로 인해 작동하지 않습니다. 실행이 시작될 때 시트가 업데이트되고 모든 것이 원활하게 실행되는 것을 볼 수 있지만 나중에 스크립트가 완료 될 때까지 고정됩니다.

다른 해결책은 MacScript 명령을 사용하는 것이지만이 셸 스크립트에는 "\"와 여러 따옴표가있는 정규식이 포함되어 있으므로이 메서드는 이미 작동하므로이 메서드를 사용하는 것이 좋습니다 . 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 코드로 변환해야합니다. Wikipedia의 “Visual Basic for Applications” 기사에 관심이 있다면 자세한 설명이 나와 있습니다.

VBA 코드는 Excel 개체에서 제공하는 메서드 나 과 같은 외부 함수보다 항상 느립니다. 예를 들어 Range Objects AutoFill Method를 사용하면 범위를 값으로 채우는 동안 VBA보다 항상 빠릅니다.

가장 좋은 방법은 "타임 아웃"코드에이 while 루프 내부의 VBA 방법 DoEvents를 추가하는 것입니다을 추가 할 수 있습니다. 이벤트를 처리하는 엑셀 및 Windows를 허용하는 While 루프의 원인이됩니다

 End If 
    VBA.DoEvents 
Wend 

이 : 그럼

나는이 같은 End If 사이 Wend 그것을에 배치 것입니다. VBA Shell() 기능을 제외하고는 VBA 코드가 순차적으로 실행됩니다. VBA.DoEvents이 없으면 코드가 완료되거나 오류가 발생할 때까지 계속 실행됩니다. 이 Stack Overflow question thread은 훌륭한 설명을 제공합니다.

코드 속도를 향상시킬 수있는 한 가지 방법은이 명령 Application.ScreenUpdating = False을 사용하여 화면 업데이트를 해제하는 것입니다. 서브의 끝에서 Application.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 초로 대기를 변경했으나, 시간이 초과되면 말리기 위해 오류를 설정해야합니다. 또한 일부 요청에서는 충분하지 않지만 5 초에서 connect-timeout을 변경하지만 대부분의 경우 1 초 미만입니다. – Matts

관련 문제