programing

VBA의 멀티스레딩

starjava 2023. 5. 7. 10:45
반응형

VBA의 멀티스레딩

여기 VBA가 여러 스레드를 실행하도록 하는 방법을 아는 사람이 있습니까?저는 엑셀을 사용하고 있습니다.

VBA로는 기본적으로 수행할 수 없습니다.VBA는 싱글 스레드 아파트에 구축됩니다.여러 스레드를 가져오는 유일한 방법은 COM 인터페이스가 있는 VBA가 아닌 다른 곳에 DLL을 구축하고 VBA에서 호출하는 것입니다.

정보: OLE 스레딩 모델의 설명 및 기능

VBA는 기본적으로 멀티스레딩을 지원하지 않지만,멀티스레딩을 수행하는 방법은 세 가지가 있습니다.

  1. COM/dll - 예:C# 및 별도의 스레드에서 실행할 병렬 클래스
  2. VBscript 작업자 스레드 사용 - 별도의 VBscript 스레드에서 VBA 코드 실행
  3. VB스크립트를 통해 실행되는 VBA 작업자 스레드 사용 - Excel 워크북을 복사하고 매크로를 병렬로 실행합니다.

여기서 모든 스레드 접근 방식을 비교했습니다. http://analystcave.com/excel-multithreading-vba-vs-vbscript-vs-c-net/

#3 접근 방식을 고려하여 VBA에 멀티스레딩을 쉽게 추가할 수 있는 VBA 멀티스레딩 툴도 만들었습니다. http://analystcave.com/excel-vba-multithreading-tool/

아래의 예를 참조하십시오.

루프용 멀티스레딩

Sub RunForVBA(workbookName As String, seqFrom As Long, seqTo As Long)
    For i = seqFrom To seqTo
        x = seqFrom / seqTo
    Next i
End Sub

Sub RunForVBAMultiThread()
    Dim parallelClass As Parallel 

    Set parallelClass = New Parallel 

    parallelClass.SetThreads 4 

    Call parallelClass.ParallelFor("RunForVBA", 1, 1000) 
End Sub

비동기식으로 Excel 매크로 실행

Sub RunAsyncVBA(workbookName As String, seqFrom As Long, seqTo As Long)
    For i = seqFrom To seqTo
        x = seqFrom / seqTo
    Next i
End Sub

Sub RunForVBAAndWait()
    Dim parallelClass As Parallel

    Set parallelClass  = New Parallel

    Call parallelClass.ParallelAsyncInvoke("RunAsyncVBA", ActiveWorkbook.Name, 1, 1000) 
    'Do other operations here
    '....

    parallelClass.AsyncThreadJoin 
End Sub

저는 비슷한 것을 찾고 있었는데 공식적인 대답은 아니오입니다.하지만, 저는 ExcelHero.com 에서 다니엘의 흥미로운 컨셉을 찾을 수 있었습니다.

기본적으로, 당신은 당신이 원하는 다양한 것들을 실행하고 그것을 엑셀로 보고하기 위해 worker vbscripts를 만들어야 합니다.다양한 웹사이트에서 HTML 데이터를 검색하는 것은 제가 하고 있는 일에 아주 좋습니다!

확인:

http://www.excelhero.com/blog/2010/05/multi-threaded-vba.html

좀 더 현대적인 언어에서 VBA로 오고 VBA에서 멀티스레딩을 검색하는 프로그래머들이 때때로 VBA의 진정한 멀티스레딩 부족을 보완하는 데 도움이 되는 몇 가지 기본 VBA 접근법을 모를 수 있기 때문에 이 답변을 추가합니다.

멀티스레딩의 동기가 장시간 실행되는 코드가 실행될 때 중단되지 않는 더 빠른 UI를 갖는 것이라면 VBA에는 실제로 작동하는 몇 가지 로우테크 솔루션이 있습니다.

사용자 양식은 모델리스로 표시할 수 있습니다. 이를 통해 양식이 열려 있는 동안 Excel과 상호 작용할 수 있습니다.이것은 실행 시 Userform의 ShowModal 속성을 false로 설정하여 지정할 수도 있고 라인을 입력하여 from loads로 동적으로 수행할 수도 있습니다.

UserForm1.Show vbModeless

사용자 양식의 초기화 이벤트입니다.

DoEvents 문입니다.이로 인해 VBA는 Excel에서 생성된 이벤트를 포함하여 이벤트 대기열의 모든 이벤트를 실행하기 위해 OS에 제어 권한을 양도합니다.일반적인 사용 사례는 코드가 실행되는 동안 차트를 업데이트하는 것입니다.DoEvents를 사용하지 않으면 매크로가 실행될 때까지 차트가 다시 칠해지지 않지만 DoEvents를 사용하면 애니메이션 차트를 만들 수 있습니다.이 아이디어의 변형은 진행률 측정기를 만드는 일반적인 방법입니다.루프 인덱스 i에 의해 제어되는 10,000,000번 실행되는 루프에서 다음과 같은 코드 섹션을 가질 수 있습니다.

If i Mod 10000 = 0 Then
    UpdateProgressBar(i) 'code to update progress bar display
    DoEvents
End If

이 중 어느 것도 멀티 스레드는 아닙니다. 하지만 경우에 따라서는 적절한 슬러지일 수도 있습니다.

Excel로 지정된 질문인 것은 알지만, Access에 대한 동일한 질문이 중복으로 표시되었기 때문에 여기에 답변을 올리겠습니다.이 원리는 간단합니다. 새 액세스 응용 프로그램을 연 다음 해당 응용 프로그램 내부에 타이머가 있는 양식을 열고, 실행할 함수/하위를 해당 양식으로 보내고, 타이머가 작동하면 작업을 실행하고, 실행이 완료되면 응용 프로그램을 종료합니다.이렇게 하면 VBA가 데이터베이스에서 테이블 및 쿼리를 사용할 수 있습니다.참고: 데이터베이스를 독점적으로 잠그면 오류가 발생합니다.

이것은 모두 VBA입니다(다른 답변과 달리).

하위/함수를 비동기적으로 실행하는 함수

Public Sub RunFunctionAsync(FunctionName As String)
    Dim A As Access.Application
    Set A = New Access.Application
    A.OpenCurrentDatabase Application.CurrentProject.FullName
    A.DoCmd.OpenForm "MultithreadingEngine"
    With A.Forms("MultiThreadingEngine")
        .TimerInterval = 10
        .AddToTaskCollection (FunctionName)
    End With
End Sub

이를 위해 필요한 양식 모듈

(양식 이름 = MultiThreading Engine, 설정된 컨트롤이나 속성이 없음)

Public TaskCollection As Collection

Public Sub AddToTaskCollection(str As String)
    If TaskCollection Is Nothing Then
        Set TaskCollection = New Collection
    End If
    TaskCollection.Add str
End Sub
Private Sub Form_Timer()
    If Not TaskCollection Is Nothing Then
        If TaskCollection.Count <> 0 Then
            Dim CollectionItem As Variant
            For Each CollectionItem In TaskCollection
                Run CollectionItem
            Next CollectionItem
        End If
    End If
    Application.Quit
End Sub

매개 변수에 대한 지원 구현은 충분히 쉬워야 하지만 값을 반환하는 것은 어렵습니다.

앞서 언급했듯이, VBA는 멀티스레딩을 지원하지 않습니다.

그러나 다른 VBA 작업자 스레드를 시작하기 위해 C# 또는 vbScript를 사용할 필요는 없습니다.

VBA를 사용하여 VBA 작업자 스레드를 만듭니다.

먼저 시작할 모든 스레드에 대한 마크로 워크북을 복사합니다.

그런 다음 Excel 인스턴스를 만들기만 하면 새 Excel 인스턴스(다른 스레드에서 실행)를 시작할 수 있습니다.응용 프로그램(오류를 방지하려면 새 응용 프로그램을 표시하도록 설정해야 합니다.)

실제로 다른 스레드에서 일부 작업을 실행하려면 마스터 워크북의 매개 변수를 사용하여 다른 응용 프로그램에서 매크로를 시작할 수 있습니다.

기다리지 않고 마스터 워크북 스레드로 돌아가려면 Application을 사용합니다.작업 스레드에서 OnTime(필요한 경우).

세마포어로서 나는 모든 스레드와 공유하는 컬렉션을 사용합니다.콜백의 경우 마스터 워크북을 작업자 스레드에 전달합니다.여기서 runMakroInOtherInstanceFunction을 다시 사용하여 콜백을 시작할 수 있습니다.

'Create new thread and return reference to workbook of worker thread
Public Function openNewInstance(ByVal fileName As String, Optional ByVal openVisible As Boolean = True) As Workbook
    Dim newApp As New Excel.Application
    ThisWorkbook.SaveCopyAs ThisWorkbook.Path & "\" & fileName
    If openVisible Then newApp.Visible = True
    Set openNewInstance = newApp.Workbooks.Open(ThisWorkbook.Path & "\" & fileName, False, False) 
End Function

'Start macro in other instance and wait for return (OnTime used in target macro)
Public Sub runMakroInOtherInstance(ByRef otherWkb As Workbook, ByVal strMakro As String, ParamArray var() As Variant)
    Dim makroName As String
    makroName = "'" & otherWkb.Name & "'!" & strMakro
    Select Case UBound(var)
        Case -1:
            otherWkb.Application.Run makroName
        Case 0:
            otherWkb.Application.Run makroName, var(0)
        Case 1:
            otherWkb.Application.Run makroName, var(0), var(1)
        Case 2:
            otherWkb.Application.Run makroName, var(0), var(1), var(2)
        Case 3:
            otherWkb.Application.Run makroName, var(0), var(1), var(2), var(3)
        Case 4:
            otherWkb.Application.Run makroName, var(0), var(1), var(2), var(3), var(4)
        Case 5:
            otherWkb.Application.Run makroName, var(0), var(1), var(2), var(3), var(4), var(5)
    End Select
End Sub

Public Sub SYNCH_OR_WAIT()
    On Error Resume Next
    While masterBlocked.Count > 0
        DoEvents
    Wend
    masterBlocked.Add "BLOCKED", ThisWorkbook.FullName
End Sub

Public Sub SYNCH_RELEASE()
    On Error Resume Next
    masterBlocked.Remove ThisWorkbook.FullName
End Sub

Sub runTaskParallel()
    ...
    Dim controllerWkb As Workbook
    Set controllerWkb = openNewInstance("controller.xlsm")

    runMakroInOtherInstance controllerWkb, "CONTROLLER_LIST_FILES", ThisWorkbook, rootFold, masterBlocked
    ...
End Sub
Sub MultiProcessing_Principle()
    Dim k As Long, j As Long
    k = Environ("NUMBER_OF_PROCESSORS")
    For j = 1 To k
        Shellm "msaccess", "C:\Autoexec.mdb"
    Next
    DoCmd.Quit
End Sub

Private Sub Shellm(a As String, b As String) ' Shell modificirani
    Const sn As String = """"
    Const r As String = """ """
    Shell sn & a & r & b & sn, vbMinimizedNoFocus
End Sub
'speed up thread
     dim lpThreadId as long
     dim test as long
     dim ptrt as long
'initparams
     ptrt=varptr(lpThreadId)
     Add = CODEPTR(thread)
'opensocket(191.9.202.255) change depending on configuration
     numSock = Sock.Connect("191.9.202.255", 1958)    
'port recieving
     numSock1=sock.open(5963)
'create thread
     hThread= CreateThread (byval 0&,byval 16384, Add , byval 0&, ByVal 1958, ptrt )
     edit3.text=str$(hThread)


' use 
Declare Function CreateThread Lib "kernel32" Alias "CreateThread" (lpThreadAttributes As long, ByVal dwStackSize As Long, lpStartAddress As Long, lpParameter As long, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long

언급URL : https://stackoverflow.com/questions/5721564/multi-threading-in-vba

반응형