MATLAB: Guardar varias variables en "-v7.3" (HDF5) .mat-files parece ser más rápido cuando se usa el indicador "-append". ¿Cómo?

NOTA: Esta pregunta trata un problema observado en 2011 con una versión anterior de MATLAB (R2009a). Según la actualización a continuación de julio de 2016, el problema / error en MATLAB parece que ya no existe (probado con R2016a; desplácese hacia abajo hasta el final de la pregunta para ver la actualización).

Estoy usando MATLAB R2009b y necesito escribir un script más grande que convierta el contenido de un conjunto más grande de archivos .zip en archivos mat v7.3 (con un modelo de datos HDF5 subyacente). Leer está bien. El problema es con el ahorro. Y en realidad no hay problema. Mis archivos se guardan bien usando elsalvar mando.

Mi pregunta es más en el sentido: ¿por qué estoy observando el siguiente comportamiento sorprendente (para mí) en MATLAB?

Veamos mi problema en general. En este escenario de prueba actual, generaré una salida: un archivo mat -v7.3. Este archivo .mat contendrá 40bloques como variables individuales Cada variable se llamará "block_NNN" del 1 al 40 y contendrá una estructura con camposmarcos ybloque No. Campomarcos contiene una secuencia 480x240x65 de datos de imagen uint8 (aquí solo datos aleatorios generados usandorandi) Campobloque No contiene el número de bloque.

Observación:En el script real (que aún no he terminado) haré lo anterior en un total de 370 veces, convirtiendo un total de 108 GB de datos sin procesar. Por eso me preocupa lo siguiente.

De todos modos, primero defino algunas variables generales:

% some sizes for dummy data and loops:
num_blockCount = 40;
num_blockLength = 65;
num_frameHeight = 480;
num_frameWidth = 240;

Luego genero un código ficticio que tiene forma y tamaño idénticos a los datos sin procesar reales:

% generate empty struct:
stu_data2disk = struct();

% loop over blocks:
for num_k = 1:num_blockCount

   % generate block-name:
   temp_str_blockName = sprintf('block_%03u', num_k);

   % generate temp struct for current block:
   temp_stu_value = struct();
   temp_stu_value.frames = randi( ...
      [0 255], ...
      [num_frameHeight num_frameWidth num_blockLength], ...
      'uint8' ...
   );
   temp_stu_value.blockNo = num_k;

   % using dynamic field names:
   stu_data2disk.(sprintf('block_%03u', num_k)) = temp_stu_value;

end

Ahora tengo todos mis datos de prueba aleatorios en una estructurastu_data2disk. Ahora me gustaría guardar los datos utilizando uno de los dos métodos posibles.

Probemos el simple primero:

% save data (simple):
disp('Save data the simple way:')
tic;
save converted.mat -struct stu_data2disk -v7.3;
toc;

El archivo está escrito sin problemas (286 MB). El resultado es:

Save data the simple way:
Elapsed time is 14.004449 seconds.

OK, entonces recordé que me gustaría seguir el procedimiento de salvar durante los 40 bloques. Por lo tanto, en lugar de lo anterior, recorro los bloques y los agrego en secuencia:

% save to file, using append:
disp('Save data using -append:')
tic;
for num_k = 1:num_blockCount

   % generate block-name:
   temp_str_blockName = sprintf('block_%03u', num_k);

   temp_str_appendToggle = '';
   if (num_k > 1)
      temp_str_appendToggle = '-append';
   end

   % generate save command:
   temp_str_saveCommand = [ ...
      'save ', ...
      'converted_append.mat ', ...
      '-struct stu_data2disk ', temp_str_blockName, ' '...
      temp_str_appendToggle, ' ', ...
      '-v7.3', ...
      ';' ...
   ];

   % evaluate save command:
   eval(temp_str_saveCommand);

end
toc;

Y nuevamente el archivo se guarda bien (286 MB). El resultado es:

Save data using -append:
Elapsed time is 0.956968 seconds.

Curiosamente, el método append es mucho más rápido?Mi pregunta es por qué

Salida dedir converted*.mat:

09-02-2011  20:38       300,236,392 converted.mat
09-02-2011  20:37       300,264,316 converted_append.mat
               2 File(s)    600,500,708 bytes

Los archivos no son idénticos en tamaño. Y una prueba confc en windows 7 reveló ... bueno, muchas diferencias binarias. Quizás los datos se modificaron un poco, por lo que esto no nos dice nada.

¿Alguien tiene una idea de lo que está pasando aquí? ¿Está el archivo adjunto utilizando una estructura de datos mucho más optimizada? ¿O tal vez Windows ha almacenado el archivo en caché y hace que el acceso sea mucho más rápido?

También hice el esfuerzo de leer los exámenes de los dos archivos. Sin presentar los números aquí, la versión adjunta fue un poco más rápida (aunque podría significar algo a la larga).

[EDITAR]: Acabo de intentar usar ningún indicador de formato (el valor predeterminado es -v7 en mi sistema) y ya no hay mucha diferencia:

Save data the simple way (-v7):
Elapsed time is 13.092084 seconds.
Save data using -append (-v7):
Elapsed time is 14.345314 seconds.

[EDITAR]: Corregí el error anterior. Anteriormente mencioné que las estadísticas eran para -v6 pero me equivoqué. Acababa de eliminar el indicador de formato y asumí que el valor predeterminado era -v6, pero en realidad es -v7.

He creado nuevas estadísticas de prueba para todos los formatos en mi sistema usando el marco fino de Andrew (todos los formatos son para los mismos datos de prueba aleatorios, ahora leídos del archivo):

15:15:51.422: Testing speed, format=-v6, R2009b on PCWIN, arch=x86, os=Microsoft Windows 7 Professional  6.1.7600 N/A Build 7600
15:16:00.829: Save the simple way:            0.358 sec
15:16:01.188: Save using multiple append:     7.432 sec
15:16:08.614: Save using one big append:      1.161 sec

15:16:24.659: Testing speed, format=-v7, R2009b on PCWIN, arch=x86, os=Microsoft Windows 7 Professional  6.1.7600 N/A Build 7600
15:16:33.442: Save the simple way:           12.884 sec
15:16:46.329: Save using multiple append:    14.442 sec
15:17:00.775: Save using one big append:     13.390 sec

15:17:31.579: Testing speed, format=-v7.3, R2009b on PCWIN, arch=x86, os=Microsoft Windows 7 Professional  6.1.7600 N/A Build 7600
15:17:40.690: Save the simple way:           13.751 sec
15:17:54.434: Save using multiple append:     3.970 sec
15:17:58.412: Save using one big append:      6.138 sec

Y los tamaños de los archivos:

10-02-2011  15:16       299,528,768 converted_format-v6.mat
10-02-2011  15:16       299,528,768 converted_append_format-v6.mat
10-02-2011  15:16       299,528,832 converted_append_batch_format-v6.mat
10-02-2011  15:16       299,894,027 converted_format-v7.mat
10-02-2011  15:17       299,894,027 converted_append_format-v7.mat
10-02-2011  15:17       299,894,075 converted_append_batch_format-v7.mat
10-02-2011  15:17       300,236,392 converted_format-v7.3.mat
10-02-2011  15:17       300,264,316 converted_append_format-v7.3.mat
10-02-2011  15:18       300,101,800 converted_append_batch_format-v7.3.mat
               9 File(s)  2,698,871,005 bytes

Por lo tanto, -v6 parece ser el más rápido para escribir. Tampoco hay grandes diferencias en el tamaño de los archivos. HDF5 tiene algún método básico de inflado incorporado hasta donde yo sé.

Hmm, ¿probablemente alguna optimización en las funciones subyacentes de escritura HDF5?

Actualmente sigo pensando que algunas funciones fundamentales de escritura HDF5 están optimizadas para agregarconjuntos de datos a un archivo HDF5 (que es lo que sucede al agregar nuevas variables a un archivo -7.3). Creo que he leído en alguna parte que HDF5 debería optimizarse de esta manera ... aunque no puedo estar seguro.

Otros detalles a tener en cuenta:

El comportamiento es muy sistémico como vemos en la respuesta de Andrew a continuación. También parece ser muy importante si ejecuta estas cosas en un ámbito local de una función o en el "global" de un script m. Mis primeros resultados fueron de un script m donde los archivos se escribieron en el directorio actual. Todavía solo puedo reproducir la escritura de 1 segundo para -7.3 en el script m. Las llamadas a funciones agregan algo de sobrecarga aparentemente.

Actualización de julio de 2016:

Encontré esto nuevamente y pensé que podría probarlo con el MATLAB más nuevo disponible en este momento. Con MATLAB R2016a en Windows 7 x64, el problema parece haberse solucionado:

14:04:06.277: Testing speed, imax=255, R2016a on PCWIN64, arch=AMD64, 16 GB, os=Microsoft Windows 7 Enterprise  Version 6.1 (Build 7601: Service Pack 1)
14:04:10.600: basic -v7.3:                    7.599 sec      5.261 GB used
14:04:18.229: basic -v7.3:                    7.894 sec      5.383 GB used
14:04:26.154: basic -v7.3:                    7.909 sec      5.457 GB used
14:04:34.096: basic -v7.3:                    7.919 sec      5.498 GB used
14:04:42.048: basic -v7.3:                    7.886 sec      5.516 GB used     286 MB file   7.841 sec mean
14:04:50.581: multiappend -v7.3:              7.928 sec      5.819 GB used
14:04:58.544: multiappend -v7.3:              7.905 sec      5.834 GB used
14:05:06.485: multiappend -v7.3:              8.013 sec      5.844 GB used
14:05:14.542: multiappend -v7.3:              8.591 sec      5.860 GB used
14:05:23.168: multiappend -v7.3:              8.059 sec      5.868 GB used     286 MB file   8.099 sec mean
14:05:31.913: bigappend -v7.3:                7.727 sec      5.837 GB used
14:05:39.676: bigappend -v7.3:                7.740 sec      5.879 GB used
14:05:47.453: bigappend -v7.3:                7.645 sec      5.884 GB used
14:05:55.133: bigappend -v7.3:                7.656 sec      5.877 GB used
14:06:02.824: bigappend -v7.3:                7.963 sec      5.871 GB used     286 MB file   7.746 sec mean

Esto fue probado con Andrew JankereproMatfileAppendSpeedup funcionar en la respuesta aceptada a continuación (5 pases con formato 7.3). Ahora,-append es igualmente lento, o más lento, para un solo guardado, como debería ser. Quizás fue un problema con una versión anterior del controlador HDF5 utilizado en R2009a.

Respuestas a la pregunta(3)

Su respuesta a la pregunta