ПРИМЕЧАНИЕ.. Этот вопрос касается проблемы, наблюдаемой еще в 2011 году со старой версией MATLAB (R2009a). Согласно обновлению, приведенному ниже с июля 2016 года, проблема/ошибка в MATLAB, похоже, больше не существует (протестировано с R2016a, прокрутите страницу до конца вопроса, чтобы увидеть обновление).
Я использую MATLAB R2009b, и мне нужно написать более крупный script, который преобразует содержимое большего набора .zip файлов в файлы макетов v7.3 (с базовой HDF5-datamodel). Чтение в порядке. Проблема заключается в экономии. И на самом деле проблем нет. Мои файлы хорошо сохраняются с помощью команды сохранить.
Мой вопрос больше в том смысле: Почему я наблюдаю следующее удивительное (для меня) поведение в MATLAB?
посмотрим на мою проблему в целом. В текущем тестовом сценарии я буду генерировать один результат: матовый файл A -v7.3. Этот .mat файл будет содержать 40 блоков в качестве отдельных переменных. Каждая переменная будет называться "block_NNN" от 1 до 40 и будет содержать структуру с фреймами полей и blockNo. Полевые рамки содержат последовательность изображений uint8 480x240x65 (здесь только случайные данные, созданные с помощью randi). Блок поляNo содержит номер блока.
Примечание: в реальном script (которого я еще не закончил) я буду делать выше всего 370 раз, конвертируя в общей сложности 108 ГБ необработанных данных. Вот почему я заинтересован в следующем.
Во всяком случае, сначала я определяю некоторые общие переменные:
% some sizes for dummy data and loops: num_blockCount = 40; num_blockLength = 65; num_frameHeight = 480; num_frameWidth = 240;
Затем я создаю некоторый фиктивный код, который имеет форму и размер, идентичные фактическим исходным данным:
% 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
Теперь у меня есть все мои случайные тестовые данные в struct stu_data2disk. Теперь я хотел бы сохранить данные, используя один из двух возможных методов.
Сначала попробуйте простой:
% save data (simple): disp('Save data the simple way:') tic; save converted.mat -struct stu_data2disk -v7.3; toc;
Файл написан без проблем (286 МБ). Выход:
Save data the simple way: Elapsed time is 14.004449 seconds.
ОК - тогда я вспомнил, что хотел бы следовать процедуре сохранения по 40 блокам. Таким образом, вместо вышеперечисленного я петлю над блоками и добавляю их последовательно:
% 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;
И снова файл сохраняет красиво (286 МБ). Выход:
Save data using -append: Elapsed time is 0.956968 seconds.
Интересно, что метод append намного быстрее? Мой вопрос: почему?
Выход из dir 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
Файлы не идентичны по размеру. И тест с fc в Windows 7 показал... много многозначных различий. Возможно, данные немного сдвинуты - это ничего нам не говорит.
Есть ли у кого-то идея, что здесь происходит? Возможно ли добавленный файл с использованием гораздо более оптимизированной структуры данных? Или, может быть, окна кэшировали файл и делают доступ к нему гораздо быстрее?
Я также попытался проверить тестовые данные из этих двух файлов. Без представления чисел здесь добавленная версия была немного быстрее (может означать что-то в конечном итоге, хотя).
[EDIT]: я просто попытался использовать флаг формата (по умолчанию - -v7 в моей системе), и больше нет никакой разницы:
Save data the simple way (-v7): Elapsed time is 13.092084 seconds. Save data using -append (-v7): Elapsed time is 14.345314 seconds.
[EDIT]: Я исправил ошибку выше. Раньше я упоминал, что статистика была для -v6, но я ошибся. Я только что удалил флаг формата и предположил, что по умолчанию был -v6, но на самом деле это -v7.
Я создал новую тестовую статистику для всех форматов в моей системе, используя прекрасную фреймворк Andrew (все форматы предназначены для тех же случайных данных теста, которые теперь читаются из файла):
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
И размеры файлов:
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
Таким образом, -v6 кажется самым быстрым для записи. Также не большие различия в размерах файлов. Насколько я знаю, у HDF5 есть какой-то базовый метод вздутия.
Хм, возможно, какая-то оптимизация в базовых функциях записи HDF5?
В настоящее время я по-прежнему считаю, что некоторые базовые функции HDF5-write оптимизированы для добавления наборов данных в HDF5 файл (что и происходит при добавлении новых переменных в файл -7.3). Я считаю, что я где-то читал, что HDF5 должен оптимизировать именно таким образом... хотя не может быть уверен.
Другие примечания:
Поведение очень системное, как мы видим в ответе Andrew ниже. Также представляется весьма важным вопрос о том, запускаете ли вы эти вещи в локальной области функции или в "глобальном" m- script. Мои первые результаты были получены из m- script, где файлы были записаны в текущий каталог. Я все еще могу воспроизвести 1-секундную запись для -7.3 в m- script. Функциональные вызовы, по-видимому, добавляют некоторые служебные данные.
Обновление июля 2016 года:
Я снова нашел это и подумал, что могу проверить его с помощью новейшего MATLAB, доступного мне на данный момент. С MATLAB R2016a в Windows 7 x64 проблема, похоже, исправлена:
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
Это было проверено с помощью функции Andrew Janke reproMatfileAppendSpeedup
в принятом ответе ниже (5 проходов с форматом 7.3). Теперь -append
будет одинаково медленным или медленным до одного сохранения - как и должно быть. Возможно, это была проблема с ранней сборкой драйвера HDF5, используемого в R2009a.