multithreading excel vba excel-vba

multithreading - Multi-threading en VBA



excel excel-vba (7)

Como probablemente hayas aprendido, VBA no es compatible nativamente con multihilo, pero Hay 3 métodos para lograr multihilo:

  1. COM / dlls - por ejemplo C # y la clase Paralelo para ejecutar en hilos separados
  2. Uso de subprocesos de trabajo de VBscript : ejecute el código de VBA en subprocesos de VBscript separados
  3. Usando hilos de trabajo de VBA ejecutados, por ejemplo, a través de VBscript , copie el libro de Excel y ejecútelo en paralelo.

Comparé todos los enfoques de subprocesos aquí: http://analystcave.com/excel-multithreading-vba-vs-vbscript-vs-c-net/

Teniendo en cuenta el enfoque n. ° 3, también creé una herramienta VBA Multithreading que le permite agregar fácilmente subprocesamiento múltiple a VBA: http://analystcave.com/excel-vba-multithreading-tool/

Vea los ejemplos a continuación:

Multithreading a For Loop

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

Ejecutar una macro de Excel de forma asíncrona

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

¿Alguien aquí sabe cómo hacer que VBA ejecute varios hilos? Estoy usando Excel.


Como se dijo antes, VBA no es compatible con Multithreading.

Pero no necesita usar C # o vbScript para iniciar otros hilos de trabajo de VBA.

Uso VBA para crear hilos de trabajo de VBA .

Primero copie el libro de trabajo makro para cada tema que quiera iniciar.

Luego puede iniciar nuevas instancias de Excel (ejecutándose en otro subproceso) simplemente creando una instancia de Excel.Application (para evitar errores, tengo que configurar la nueva aplicación para que sea visible).

Para ejecutar realmente alguna tarea en otro hilo, puedo iniciar un makro en la otra aplicación con los parámetros del libro maestro.

Para volver al hilo del libro maestro sin esperar, simplemente uso Application.OnTime en el hilo del trabajador (donde lo necesito).

Como semáforo simplemente uso una colección que se comparte con todos los hilos. Para las devoluciones de llamada, pase el libro maestro al hilo de trabajo. Allí la función runMakroInOtherInstance puede reutilizarse para iniciar una devolución de llamada.

''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


Estaba buscando algo similar y la respuesta oficial es no. Sin embargo, pude encontrar un concepto interesante de Daniel en ExcelHero.com.

Básicamente, necesita crear vbscripts de trabajo para ejecutar las diversas cosas que desea y hacer que informe a excel. Por lo que estoy haciendo, recuperando datos HTML de varios sitios web, ¡funciona genial!

Echar un vistazo:

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


Estoy agregando esta respuesta ya que los programadores que vienen a VBA desde idiomas más modernos y buscan para multithreading en VBA podrían desconocer un par de enfoques nativos de VBA que a veces ayudan a compensar la falta de multithreading verdadero de VBA.

Si la motivación del multihilo es tener una interfaz de usuario más receptiva que no se cuelga cuando se ejecuta el código de ejecución prolongada, VBA sí tiene un par de soluciones de baja tecnología que a menudo funcionan en la práctica:

1) Se puede hacer que las formas de usuario se muestren sin moderación, lo que permite al usuario interactuar con Excel mientras el formulario está abierto. Esto puede especificarse en tiempo de ejecución configurando la propiedad ShowModal del Userform en false o puede hacerse de forma dinámica a medida que la carga se realiza colocando la línea

UserForm1.Show vbModeless

en el evento de inicialización del formulario de usuario.

2) La declaración DoEvents. Esto hace que VBA ceda el control al sistema operativo para ejecutar cualquier evento en la cola de eventos, incluidos los eventos generados por Excel. Un caso de uso típico es actualizar un gráfico mientras el código se está ejecutando. Sin DoEvents, el gráfico no se volverá a pintar hasta que se ejecute la macro, pero con Doevents puede crear gráficos animados. Una variación de esta idea es el truco común de crear un medidor de progreso. En un bucle que se ejecutará 10,000,000 de veces (y controlado por el índice de bucle i ) puede tener una sección de código como:

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

Nada de esto es multihilo, pero podría ser un error adecuado en algunos casos.


Sé que la pregunta especifica Excel, pero dado que la misma pregunta para Access se marcó como duplicada, entonces publicaré mi respuesta aquí. El principio es simple: abra una nueva aplicación de Access, luego abra un formulario con un temporizador dentro de esa aplicación, envíe la función / sub que desea ejecutar a ese formulario, ejecute la tarea si el temporizador acierta y salga de la aplicación una vez que la ejecución terminado. Esto permite que VBA trabaje con tablas y consultas desde su base de datos. Nota: arrojará errores si ha bloqueado exclusivamente la base de datos.

Esto es todo VBA (a diferencia de otras respuestas)

La función que ejecuta un sub / función de forma asíncrona

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

El módulo del formulario requerido para lograr esto

(nombre del formulario = MultiThreadingEngine, no tiene controles ni propiedades establecidas)

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

La implementación del soporte para parámetros debería ser lo suficientemente fácil, sin embargo, la devolución de valores es difícil.



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