2010-11-24 15 views
8

Tengo una función que tarda mucho en ejecutarse. Cuando lo perfilo, me parece que más de la mitad del tiempo (26 de 50 segundos) no se tiene en cuenta en el desglose de línea por línea, y puedo mostrar que el tiempo se gasta después de que la función termina pero antes de que regrese el control por el siguiente método:MATLAB tarda mucho tiempo después de la última línea de una función

ts1 = tic; 
disp ('calling function'); 
functionCall(args); 
disp (['control returned to caller - ', num2str(toc(ts1))]); 

la primera línea de la función que llamo es ts2 = tic, y la última línea es

disp (['last line of function- ', num2str(toc(ts2))]); 

el resultado es

llamando funcio n

última línea de la función - 24.0043

de control regresó a la persona que llama - 49,857

hurgando en la interwebs, creo que esto es un síntoma de la forma en MATLAB administra la memoria. Desasigna los retornos de funciones y, a veces, esto lleva mucho tiempo. La función asigna algunas matrices grandes (~ 1 millón de elementos). También funciona con identificadores, pero no crea ningún objeto nuevo de manejador o manejador de tienda explícitamente. Mis preguntas son:

  1. ¿Es esto definitivamente un problema de gestión de memoria?
  2. ¿Hay alguna forma sistemática de diagnosticar qué causa un problema en esta función, a diferencia de otras que regresan rápidamente?
  3. ¿Hay consejos generales para reducir la cantidad de tiempo que MATLAB pasa limpiando en una salida de función?
+2

Ningún miembro del personal de MathWorks se ha ocupado de responder esta pregunta hasta el momento. Por lo tanto, reconocen silenciosamente que es un defecto de diseño fundamental de MATLAB. – Mikhail

Respuesta

2

he descubierto una solución a mi problema específico que pueda ser aplicable en general.

La función que tardaba mucho en salir se invocaba en un objeto básico que contenía un vector de objetos de controlador. Cuando cambié la definición del objeto básico para extender el identificador, eliminé el rezago al final de la función.

Lo que creo que estaba sucediendo es esto: cuando pasé el objeto básico a mi función, creó una copia de ese objeto (MATLAB es pasar por valor de forma predeterminada). Esto no lleva mucho tiempo, pero cuando la función salió, destruyó la copia del objeto, lo que provocó que mirara a través del vector de los objetos del controlador para asegurarse de que no había ningún huérfano que debía limpiarse. Creo que es esta operación la que le tomó a MATLAB mucho tiempo.

Cuando cambié el objeto que estaba pasando a un identificador, no se realizó ninguna copia en el área de trabajo de la función, por lo que no se requirió limpieza del objeto al final.

Esto sugiere una regla general para mí:

Si una función está tomando mucho tiempo para limpiar su área de trabajo a la salida y se le pasa una gran cantidad de datos o estructuras complejas por valor, tratar encapsular los argumentos a esa función en un objeto

Esto evita la duplicación y, por lo tanto, lleva mucho tiempo de limpieza al salir. La desventaja es que su función ahora puede cambiar inesperadamente sus entradas, porque MATLAB no tiene la capacidad de declarar un argumento const, como en C++.

+0

MATLAB no tiene un valor por defecto, vea esta publicación: http://blogs.mathworks.com/loren/2006/05/10/memory-management-for-functions-and-variables/. Pero aparentemente esta regla no se aplica para objetos de valor. – Mikhail

+0

El comportamiento de MATLAB es pasable por valor de forma predeterminada. Entonces, si hay un vector de objetos hadle, y usted hace un cambio en ese vector en una función, MATLAB necesita lidiar con las consecuencias de ese cambio al salir, incluso si la implementación interna no hizo una copia de ese vector. Probablemente, esto significa que cuando se llama a la función, el contador de referencia en los objetos se incrementa en uno, y cuando la función sale, el contador de referencia disminuye en uno. Esto debería ser rápido, pero probablemente no sea así con alguna otra parte del esquema de Matlab, especialmente con objetos anidados y recursivos. – Marc

4

Tiene razón, parece ser el tiempo dedicado a garbage collection. Me temo que es un defecto fundamental de MATLAB, se conoce desde hace años, pero MathWorks no lo ha resuelto ni siquiera en la versión más nueva de MATLAB 2010b.

Puede intentar establecer las variables manualmente en [] antes de abandonar la función, es decir, realizar la recolección de basura manualmente. Esta técnica también ayuda a against memory fugas en versiones anteriores de MATLAB. Ahora MATLAB pasado tiempo no en end sino en myVar=[];

Se podría aliviar de trabajo problema sin ningún tipo de referencias - funciones anónimas, funciones anidadas, manejar clases, no usar cellfun y arrayfun.

Si ha llegado a la "barrera del rendimiento" de MATLAB, entonces tal vez debería simplemente cambiar el entorno. De todos modos, no veo sentido comenzar hoy un nuevo proyecto en MATLAB, excepto si está usando SIMULINK. Python busca la computación técnica y con C# también puedes hacer muchas cosas que MATLAB hace usando free libraries. Y ambos son reales lenguajes de programación y son gratuitos, a diferencia de MATLAB.

+0

¿MyVar = [] es superior a clear myVar? Intenté borrar todas las variables excepto la función return (usando whos para determinar los nombres de las variables en el área de trabajo) antes de salir, pero no ayuda. – Marc

+0

No sé, pruébalo y publica tus conclusiones. ¿Qué versión de MATLAB estás usando? – Mikhail

0

Una solución simple podría ser esta: asignar previamente las matrices grandes y pasarlas como argumentos a tu functionCall(). Esto traslada el problema de desasignación a la persona que llama a functionCall(), pero podría ser que esté llamando a functionCall con más frecuencia que su principal, en cuyo caso esto acelerará su código.

workArr = zeros(1,1e6); % allocate once 
... 
functionCall(args,workArr); % call with extra argument 
... 
functionCall(args,wokrArr); % call again, no realloc of workArr needed 
... 

Dentro FunctionCall que puede hacerse cargo de la inicialización y/o re-establecer workArr, por ejemplo

[workArr(:)] = 0; % reset work array 
+2

Esto no es probable que ayude en la mayoría de las situaciones. Tan pronto como functionCall modifique workArr, MATLAB creará una copia de workArr para almacenar los cambios realizados en functionCall. El resultado es que el consumo de memoria se duplica y se desperdicia tiempo realizando la copia. Si workArr es un objeto de control, este enfoque _ podría ser una mejora. Benchmarking es ciertamente necesario en este caso. –

Cuestiones relacionadas