При написании большого массива непосредственно на диске в MATLAB существует ли необходимость перераспределения?

Мне нужно написать массив, который слишком велик, чтобы вставлять в память двоичный файл .mat. Это можно сделать с помощью функции matfile, которая позволяет произвольный доступ к файлу .mat на диске.

Обычно принятый совет состоит в том, чтобы предварительно распределить массивы, потому что расширение их на каждой итерации цикла происходит медленно. Однако, когда я был спрашивая, как это сделать, мне пришло в голову, что это может быть не хорошим советом при записи на диск, а не в ОЗУ.

Будет ли та же самая производительность при использовании массива применяться, а , если, будет значимо, когда по сравнению с время, которое требуется для записи на диск?

(Предположим, что весь файл будет записан за один сеанс, поэтому риск серьезной фрагментации файла низкий.)

Ответ 1

Q: Будет ли такая же производительность влиять на рост массива, и если это так, то это будет значительным по сравнению с временем, которое требуется для записи на диск?

A: Да, производительность будет страдать, если вы значительно увеличите файл на диске без предварительного выделения. Снижение производительности будет следствием фрагментации. Как вы уже упоминали, фрагментация менее опасна, если файл написан за один сеанс, но вызовет проблемы, если файл значительно возрастет.

A связанный вопрос был поднят на веб-сайте MathWorks, и принятый ответ состоял в том, чтобы предварительно выделить, когда это возможно.

Если вы не предварительно выделите, то степень ваших проблем с производительностью будет зависеть от:

  • ваша файловая система (как данные хранятся на диске, размер кластера),
  • ваше оборудование (время поиска HDD или время доступа SSD),
  • размер вашего файла мата (перемещается ли он в несмежное пространство),
  • и текущее состояние вашего хранилища (существующая фрагментация/свободное пространство).

Предположим, что вы используете последнюю ОС Windows, и поэтому используете файловую систему NTFS. Предположим далее, что он был настроен с размером кластера по умолчанию 4 КБ. Таким образом, пространство на диске распределяется в 4 kB chunks, и их местоположения индексируются в таблицу основных файлов. Если файл растет, и смежное пространство недоступно, есть только два варианта:

  • Перепишите весь файл на новую часть диска, где есть достаточное свободное пространство.
  • Фрагмент файла, сохраняющий дополнительные данные в другом физическом месте на диске.

Файловая система решает сделать параметр наименьшего значения, № 2, и обновляет запись MFT, чтобы указать, где новые кластеры будут на диске.

Illustration of fragmented file on NTFS, from WindowsITPro

Теперь жесткому диску необходимо физически переместить читаемую головку, чтобы читать или писать новые кластеры, и это (относительно) медленный процесс. С точки зрения перемещения головы и ожидания того, что правая область диска будет вращаться под ним... вы, вероятно, будете искать время поиска около 10 мс. Таким образом, каждый раз, когда вы нажимаете фрагмент, будет задержка в 10 мс, пока жесткий диск перемещается для доступа к новым данным. У SSD намного меньше времени поиска (без движущихся частей). Для простоты мы игнорируем многодисковые системы и массивы RAID!

Если вы продолжаете размножать файл в разное время, вы можете столкнуться с большим количеством фрагментации. Это действительно зависит от того, когда/сколько увеличивается файл, и как еще вы используете жесткий диск. Эффект, который вы испытываете, также зависит от того, как часто вы читаете файл и как часто вы сталкиваетесь с фрагментами.

MATLAB хранит данные в "Порядок столбцов" , и из комментариев кажется, что вы заинтересованы в выполнении операций с столбцами ( суммы, средние) в наборе данных. Если столбцы становятся несмежными на диске, вы нажмете много фрагментов на каждой операции!

Как указано в комментариях, оба действия чтения и записи будут выполняться через буфер. Поскольку @user3666197 указывает, что ОС может спекулятивно читать перед текущими данными на диске, на основе того, что вы, скорее всего, захотите, чтобы эти данные были следующими. Такое поведение особенно полезно, если жесткий диск будет сидеть в режиме ожидания, а его работа на максимальной мощности и работа с небольшими частями данных в буферной памяти может значительно улучшить производительность чтения и записи. Однако из вашего вопроса звучит так, как будто вы хотите выполнять большие операции над огромным (слишком большим для памяти).mat файлом. Учитывая ваш прецедент, жесткий диск будет работать в любом случае, и файл данных слишком велик, чтобы вписаться в буфер, поэтому эти конкретные трюки не решают вашу проблему.

Итак... Да, вы должны предварительно выделить. Да, будет применен удар производительности от создания массива на диске. Да, это, вероятно, будет значительным (это зависит от особенностей, таких как рост, фрагментация и т.д.). И если вы действительно подойдете к духу вещей HPC, остановите то, что вы делаете, выбросьте MATLAB, обманите свои данные и попробуйте что-то вроде Apache Spark! Но это еще одна история.

Отвечает ли это на ваш вопрос?

P.S. Исправления/поправки приветствуются! Я был воспитан на POSIX inodes, поэтому искренние извинения, если здесь есть какие-то неточности...

Ответ 2

Предопределение переменной в ОЗУ и предварительное распределение на диске не решают одну и ту же проблему.

В оперативной памяти

Чтобы развернуть матрицу в ОЗУ, MATLAB создает новую матрицу с новым размером и копирует значения старой матрицы в новую и удаляет старую. Это стоит большой производительности.

Если вы предварительно выделили матрицу, размер ее не изменится. Таким образом, больше нет причин для MATLAB делать это копирование матрицы больше.

На жестком диске

Проблема на жестком диске - фрагментация, как сказал GnomeDePlume. Фрагментация по-прежнему будет проблемой, даже если файл написан за один сеанс.

Вот почему: жесткий диск обычно будет немного фрагментирован. Представьте себе

  • # - блоки памяти на жестком диске, полные
  • M - блоки памяти на жестком диске, которые будут использоваться для сохранения данных вашей матрицы.
  • - - свободные блоки памяти на жестком диске

Теперь жесткий диск может выглядеть так, как только вы напишете на нем матрицу:

###--##----#--#---#--------------------##-#---------#---#----#------

Когда вы пишете части матрицы (например, MMM blocks), вы можете представить, как процесс выглядит так > ! (Приведем пример, где файловая система будет просто идти слева направо и использовать первое свободное пространство это достаточно большое - реальные файловые системы разные):

  • Первая матричная часть:
    ###--##MMM-#--#---#--------------------##-#---------#---#----#------
  • Вторая матричная часть: ###--##MMM-#--#MMM#--------------------##-#---------#---#----#------
  • Третья матричная часть: ###--##MMM-#--#MMM#MMM-----------------##-#---------#---#----#------
  • И так далее...

Очевидно, что файл матрицы на жестком диске фрагментирован, хотя мы написали его, не делая ничего другого.

Это может быть лучше, если файл матрицы был предварительно назначен. Другими словами, мы сообщаем файловой системе, насколько большим будет наш файл, или в этом примере, сколько блоков памяти мы хотим зарезервировать для него.

Представьте себе, что для матрицы необходимы 12 блоков: MMMMMMMMMMMM. Мы сообщаем файловой системе, что нам так нужно, предварительно распределяя ее, и она будет стараться максимально удовлетворить наши потребности. В этом примере нам повезло: есть свободное пространство s >= 12 блоками памяти.

  • Предопределение (требуется 12 блоков памяти):
    ###--##----#--#---# (------------) --------##-#---------#---#----#------
    Файловая система резервирует пространство между круглыми скобками для нашей матрицы и будет записывать туда.
  • Первая матричная часть:
    ###--##----#--#---# (MMM---------) --------##-#---------#---#----#------
  • Вторая матричная часть:
    ###--##----#--#---# (MMMMMM------) --------##-#---------#---#----#------
  • Третья матричная часть:
    ###--##----#--#---# (MMMMMMMMM---) --------##-#---------#---#----#------
  • Четвертая и последняя часть матрицы:
    ###--##----#--#---# (MMMMMMMMMMMM) --------##-#---------#---#----#------

Voilá, без фрагментации!


Аналогия

Как правило, вы можете представить этот процесс как покупку билетов в кино для большой группы. Вы хотели бы держаться вместе как группа, но в театре уже есть некоторые места, зарезервированные другими людьми. Для того, чтобы кассир мог соответствовать вашему запросу (большая группа хочет придерживаться вместе), ему нужны знания о том, насколько велика ваша группа (preallocating).

Ответ 3

A быстрый ответ на все обсуждение (если у вас нет времени для выполнения или технического понимания):

  • Предварительное распределение в Matlab относится к операциям в ОЗУ. Matlab не обеспечивает низкоуровневый доступ к операциям ввода-вывода, и поэтому мы не можем говорить о предварительном размещении чего-либо на диске.
  • При записи большого количества данных на диск было замечено, что чем меньше количество записей, тем быстрее выполняется выполнение задачи, а меньше - фрагментация на диске.

Таким образом, если вы не можете писать за один раз, разделите записи в больших кусках.

Ответ 4

Пролог

Этот ответ основан как на исходном сообщении, так и на пояснениях (оба), предоставленных автором в течение последней недели.

Вопрос о неблагоприятной производительности: (s) , представленный низкоуровневой, физически-зависимой средой, "фрагментацией введенный как файловыми системами, так и файловыми уровнями доступа , больше встречается как в значениях TimeDOMAIN, так и в ComputingDOMAIN повторяемости этих с реальными проблемами такого подхода.

Наконец было предложено современное, максимально быстрое решение данной задачи, чтобы свести к минимуму ущерб как от потерь, так и от ошибок неправильной интерпретации из идеализированных или иных недостоверных предположений, так как риск "серьезной фрагментации файла является низким" из-за предположения, что весь файл будет записан за один сеанс (который просто принципиально невозможен во время много многоядерных/многопроцессорных операций современного O/S в режиме реального времени в течение времени создания и последовательности обширных модификаций (см. ограничения размера MATLAB) файла BLOB размера TB -объект внутри современных файловых систем COTS).


Можно ненавидеть факты, однако факты остаются верными там, пока более быстрый и лучший метод не движется в


Во-первых, прежде чем рассматривать производительность, воспользуйтесь пробелами в концепции

  • Негативное вредоносное воздействие производительности не вызвано с помощью HDD-IO или связано с фрагментацией файла

  • ОЗУ не является альтернативой для полупостоянного хранилища файла .mat

  • Дополнительные ограничения операционной системы и вмешательства + дополнительные абстракции на основе драйверов и аппаратных средств были проигнорированы из предположений о непроизводительных накладных расходах
  • Указанная вычислительная схема была исключена из обзора того, что будет иметь наибольшее влияние/влияние на результативность

Дано:

  • Вся обработка предназначена для запуска только один раз, без оптимизации/итераций, без непрерывной обработки

  • Данные имеют 1E6 double Значения Float x 1E5 столбцы = около 0.8 TB (+ HDF5 служебные)

  • Несмотря на исходное сообщение, существует не случайный IO, связанный с обработкой

  • Фаза получение связывается с .NET для получения DataELEMENT в MATLAB

    Это означает, что поскольку v7.4,

    a 1.6 GB limit на MATLAB WorkSpace в 32-битной Win (2,7 ГБ с 3-гигабайтным коммутатором)

    a 1.1 GB limit на Матрица MATLAB в wXP/1.4 GB wV/1.5 GB

    бит "выпущен" 2.6 GB limit на MATLAB WorkSpace + 2.3 GB ограничивает самую большую матрицу в 32-битном Linux O/S.

    Наличие 64-битного O/S не поможет никакому 32-битовому внедрению MATLAB 7.4 и не сможет работать из-за другого ограничения, максимальное количество ячеек в массиве, которое не будет охватывать 1E12 здесь.

    Единственный шанс - иметь оба

  • Фаза хранения предполагает блок-запись упорядоченных по строкам блоков данных (набор упорядоченных по строкам блоков данных) в MAT-file на HDD-устройстве

  • Фаза обработки предполагает перепрограммирование данных в MAT-file на HDD-устройстве после того, как все входы были получены и распределены в файловую систему вне RAM -storage, но упорядоченным по порядку образом

  • just column-wise mean() -s/max() -es необходимы для вычисления (не более сложного)

Факты:

  • MATLAB использует "ограниченную" реализацию файловой структуры HDF5 для двоичных файлов.

Просмотрите измерения производительности на реальных данных и реальных аппаратных средствах (HDD + SSD), чтобы получить ощущение масштабов неустранимых слабых мест

Иерархический формат данных (HDF) родился в 1987 году в Национальном центре приложений Суперкомпьютер ( NCSA) около 20 лет назад. Да, этот старый. Цель заключалась в разработке формата файла, который сочетает гибкость и эффективность для работы с чрезвычайно большими наборами данных. Так или иначе, файл HDF не использовался в основном потоке, так как только несколько отраслей действительно могли действительно использовать его ужасающие возможности или просто не нуждались в них.

ГИБКОСТЬ означает, что файловая структура несет некоторые накладные расходы, не нужно использовать, если содержимое массива не изменяется (вы оплачиваете стоимость, не тратя на это никакой пользы от его использования) и предположение, что HDF5 ограничения на общий размер данных, которые он может содержать в себе, помогают и сохраняют сторону MATLAB проблемы, являются неправильными.

MAT-files хороши в принципе, так как они избегают постоянной необходимости загружать целый файл в ОЗУ, чтобы иметь возможность работать с ним.

Тем не менее, MAT-files не служат простой задачей, как было определено и разъяснено здесь. Попытка сделать это приведет к снижению производительности и фрагментации файлов HDD-IO (добавление нескольких десятков миллисекунд во время write-through -s и что-то меньшее, чем на read-ahead -s во время вычислений) не поможет вообще судить основную причину для общей плохой производительности.


Профессиональный подход к решению

Вместо того, чтобы перемещать весь гигантский набор 1E12 DataELEMENT в массив данных прокси-сервера MATLAB в памяти, который запланирован только для следующего следующего потока последовательности HDF5/MAT-file IO-s устройства жесткого диска (write-through и O/S по сравнению с аппаратно-устройством-цепочкой, конфликтующим/под-оптимизированным read-ahead), чтобы все работающие "просто [женатые] были готовы" для нескольких и тривиально простые вызовы функций mean()/ max() MATLAB (которые сделают все возможное, чтобы обновить каждый из 1E12 DataELEMENT только в другом порядке (и даже TWICE - yes - еще один цирк сразу после первого кошмара для обработки работы до конца, через все узкие места HDD-IO strong > ) обратно в объекты MATLAB в ОЗУ, сделать редизайн этот самый шаг в обработке BigDATA на трубной линии с самого начала.

while true                                          % ref. comment Simon W Oct 1 at 11:29
   [ isStillProcessingDotNET,   ...                 %      a FLAG from .NET reader function
     aDotNET_RowOfVALUEs ...                        %      a ROW  from .NET reader function
     ] = GetDataFromDotNET( aDtPT )                 %                  .NET reader
   if ( isStillProcessingDotNET )                   % Yes, more rows are still to come ...
      aRowCOUNT = aRowCOUNT + 1;                    %      keep .INC for aRowCOUNT ( mean() )
      for i = 1:size( aDotNET_RowOfVALUEs )(2)      %      stepping across each column
         aValue     = aDotNET_RowOfVALUEs(i);       %      
         anIncrementalSumInCOLUMN(i) = ...
         anIncrementalSumInCOLUMN(i) + aValue;      %      keep .SUM for each column ( mean() )
         if ( aMaxInCOLUMN(i) < aValue )            %      retest for a "max.update()"
              aMaxInCOLUMN(i) = aValue;             %      .STO a just found "new" max
         end
      endfor
      continue                                      %      force re-loop
   else
      break
   endif
end
%-------------------------------------------------------------------------------------------
% FINALLY:
% all results are pre-calculated right at the end of .NET reading phase:
%
% -------------------------------
% BILL OF ALL COMPUTATIONAL COSTS ( for given scales of 1E5 columns x 1E6 rows ):
% -------------------------------
% HDD.IO:          **ZERO**
% IN-RAM STORAGE:
%                  Attr Name                       Size                     Bytes  Class
%                  ==== ====                       ====                     =====  =====
%                       aMaxInCOLUMNs              1x100000                800000  double
%                       anIncrementalSumInCOLUMNs  1x100000                800000  double
%                       aRowCOUNT                  1x1                          8  double
%
% DATA PROCESSING:
%
% 1.000.000x .NET row-oriented reads ( same for both the OP and this, smarter BigDATA approach )
%         1x   INT   in aRowCOUNT,                 %%       1E6 .INC-s
%   100.000x FLOATs  in aMaxInCOLUMN[]             %% 1E5 * 1E6 .CMP-s
%   100.000x FLOATs  in anIncrementalSumInCOLUMN[] %% 1E5 * 1E6 .ADD-s
% -----------------
% about 15 sec per COLUMN of 1E6 rows
% -----------------
%                  --> mean()s are anIncrementalSumInCOLUMN./aRowCOUNT
%-------------------------------------------------------------------------------------------
% PIPE-LINE-d processing takes in TimeDOMAIN "nothing" more than the .NET-reader process
%-------------------------------------------------------------------------------------------

Ваша стратегия d BigDATA будет разумно избегать промежуточной буферизации хранилища в MATLAB, поскольку она будет постепенно вычислять результаты не более чем на 3 x 1E6 ADD/CMP-регистры, все со статическим расположением, избегать прокси-хранилища в HDF5/MAT-file, полностью избегать все узкие места, связанные с HDD-IO, и низкие скорости чтения BigDATA с постоянным считыванием (не говоря уже о промежуточной /BigDATA устойчивой записи...) и будут также избегать неэффективного использования памяти просто для подсчета средних значений s и max.


Эпилог

Обработка трубопровода не является чем-то новым под Солнцем.

Он повторно использует то, что высокопроизводительные решения HPC уже используют в течение десятилетий

[поколения до того, как тег BigDATA был "изобретен" в отделе маркетинга. ]

Забудьте о zillions операций блокировки HDD-IO и перейдите в конвейерное распределенное решение для процесса.


Нет ничего быстрее, чем этот


Если бы это было, все FX-бизнес и HFT-хедж-фонд Monsters уже были там...