2009-08-18 20 views
5

Tengo un modelo de Excel que usa casi todas las UDF. Hay, por ejemplo, 120 columnas y más de 400 filas. Los cálculos se realizan verticalmente y luego horizontalmente, es decir, primero se hacen todos los cálculos para la columna 1, luego el resultado final de la columna 1 es la entrada de la columna 2, etc. En cada columna llamo alrededor de seis o siete UDF que llamar a otras UDF. Las UDF suelen generar una matriz.Funciones definidas por el usuario en Excel y problemas de velocidad

Las entradas para cada una de las UDF son un número de variables, algunas variables de rango, algunas dobles. Las variables de rango se convierten a matrices internamente antes de acceder a sus contenidos.

Mi problema es el siguiente, puedo construir el modelo Excel sin UDF y cuando ejecuto simulaciones, puedo finalizar todos los cálculos en X horas. Cuando uso UDF, el tiempo de simulación es de 3X horas o más. (Para responder a la pregunta obvia, sí, tengo que trabajar con UDF porque si quiero hacer pequeños cambios en el modelo (por ejemplo, agregar otro tipo de activo (es un modelo financiero)) se tarda casi un día en rehacer el modelo. sin UDF para ajustarse a la nueva estructura legal/financiera, con UDF se necesitan aproximadamente 20 minutos para acomodar una estructura financiera diferente.)

En cualquier caso, he desactivado la actualización de pantalla, no hay copia y pegado en las funciones , el uso de tipos de variantes es mínimo, todos los datos están contenidos en una hoja, convierto todas las variables de tipo de rango a las matrices antes de obtener los contenidos.

¿Qué más puedo hacer que no sea obtener una computadora más rápida o su equivalente para hacer que el código de VBA/archivo Excel funcione más rápido? Por favor, avíseme si esto necesita más aclaración.

Gracias!

+0

¿Puedes publicar una función aquí? o una versión simplificada para que podamos echar un vistazo? –

+0

wow, no pensé que obtendría respuestas tan rápido. Veré si puedo publicar una versión simplificada de lo que sucede en algún momento de la semana. gracias por los mensajes! –

+0

Parece que podría estar en el punto en el que el programador-sobrecarga para codificar sus UDF en C y empaquetarlas en un XLL vale la pena para ahorrar la sobrecarga de ejecución de llamar a un montón de UDF de VBA ... – jtolle

Respuesta

1

controlar y minimizar los nuevos cálculos con

wks.EnableCalculation = False 

o

Application.Calculation = xlCalculationManual 

Además, minimizar los intercambios entre VBA y los libros de trabajo. Es más rápido de leer y escribir bloques de celdas a la vez en una matriz

MyArray = range("B2:B20000") 

en lugar de celda por celda (para cada uno ...).

+0

ah sí, debería haber mencionado, el cálculo se estableció en manual. desafortunadamente, la naturaleza de los cálculos requiere que no pueda tomar todo el rango como entrada por adelantado. funciona así, func1 (A1: A5) genera salidas a A6: A10, luego func2 (A6: A10) genera salidas a A11: A15, etc. –

+0

también puede usar Rango ("xxx"). Calcular si es necesario –

4

Par de consejos generales.

  1. Asuma su función y averigüe dónde están realmente los cuellos de botella. Consulte esta pregunta para el use of timer en excel. Estoy seguro de que hay perfiladores de VBA por ahí ... pero probablemente no necesites llegar tan lejos. (NB: hacer esto con una celda de datos en primer lugar ...)

  2. Piense en su diseño ... 400x120 celdas de datos es no mucho. Y para que tome horas que debe ser doloroso. (En el pasado lo he descifrado después de esperar un minuto para 1,000s de VLOOKUPS() para devolver) de todos modos, tal vez en lugar de tener una pila de UDF, ¿por qué no tener una subrutina simple que for..each en el rango y hace lo que necesita? que hacer. 48,000 celdas podrían tomar segundos o tal vez solo minutos. A continuación, puede asociar la subrutina con un botón o elemento de menú para el usuario.

Fuera de interés que tuve un rápido vistazo a la opción 2 y crearon myudf(), utilizando el sub DoMyUDF() llamarlo para la selección activa trabajado 10 veces más rápido para mí, que teniendo la UDF de cada célula .

Option Explicit 



Function MyUDF(myVar As Variant) As Variant 
    MyUDF = myVar * 10 
End Function 

Sub DoMyUDF() 
    Dim r As Range 
    Dim c As Variant 

    Dim t As Single 
    t = Timer 


    If TypeName(Selection) <> "Range" Then 
    Exit Sub 
    End If 


    Set r = Selection.Cells 

    Application.DisplayStatusBar = True 

    For Each c In r 
    c.Value = MyUDF(c.Value) 

    Application.StatusBar = "DoMyUDF(): " & Format(Timer - t, "#0.0000ms") 
    Next 

    Debug.Print "DoMyUDF(): " & Format(Timer - t, "#0.0000ms") 

End Sub 

Si reemplaza MyUDF() con su UDF esto sólo podrían ahorrarle 4,5 minutos ... pero es posible que haya algunas otras economías se puede construir en. Especialmente si usted está repitiendo los mismos calculadoras una y otra vez.

+0

interesante, Voy a probar esto. el problema es que mientras 120x400 celdas de datos no son muchas, tengo que hacer más de 30,000 simulaciones. en el pasado, pude hacer esto dentro de una hora (sin UDF), pero en este momento me toma aproximadamente 3 horas. voy a probar sus sugerencias y ver qué pasa. Mientras tanto, ¡gracias por tomarse el tiempo para responder! –

+0

También puede hacer las cosas un poco más rápidas cargando una matriz variante en el rango usado de su hoja de cálculo, luego rellene esa matriz con valores de celda y coloque esa matriz variante como el valor de la variable utilizada. Esto es significativamente más rápido que decirle a Excel que rellene cada celda individual con un valor de uno en uno ... –

2

Hay un error de ralentización en la forma en que Excel maneja las UDF. Cada vez que se calcula un UDF, Excel actualiza la barra de título de VBE (puede verlo parpadear). Para un gran número de UDF, esto es muy lento. El bypass es muy simple en el modo de cálculo manual: simplemente inicie el cálculo desde VBA usando algo como Application.Calculate (puede atrapar F9, etc. con OnKey).

ver http://www.decisionmodels.com/calcsecretsj.htm para obtener más detalles.

+0

+1 para el enlace, sería +1 por ser el propietario del enlace. – jtolle

3

¿Ha considerado reemplazar la UDF (que recibe el nombre de una vez por celda de salida) por una macro, que puede operar en un rango de celdas en un bucle?

UDF instalación/desmontaje es muy lento, y nada cada llamada UDF hace en común con otros UDF (lectura de las entradas superpuestas, por ejemplo) se convierte en un esfuerzo extra.

Pude mejorar el rendimiento 10-50x al hacer esto: hace menos de un mes tuve una hoja de cálculo con 4000-30000 llamadas UDF, las reemplacé con una sola macro que opera en algunos rangos nombrados .

Cuestiones relacionadas