как обрабатывать большой объем данных с плавающей точкой?

#java

#java

Вопрос:

У нас есть двоичный файл, который содержит большой объем float данных (около 80 МБ). нам нужно обработать это в нашем Java-приложении. Данные получены с медицинского сканера. Один файл содержит данные из одного Rotation . Один из них Rotation содержит 960 Views . Один View содержит 16 Rows , а другой Rows содержит 1344 Cells . Эти числа (их взаимосвязь) фиксированы.

Нам нужно прочитать ВСЕ значения с плавающей запятой в нашем приложении со структурой кода, отражающей приведенную выше структуру о Rotation-view-row-cell .

Что мы делаем сейчас, так это используем float[] для хранения данных для Cells , а затем используем ArrayList для Rotation , View и Row для хранения их данных.

У меня есть два вопроса:

  1. как быстро заполнить данные ячейки (считывать значения с плавающей точкой в нашем float[])?
  2. у вас есть идея получше, как хранить эти данные?

Ответ №1:

  1. Используйте DataInputStream (и его readFloat() метод), обертывающий a FileInputStream , возможно, с e BufferedInputStream между ними (попробуйте, улучшает ли буфер производительность или нет).
  2. Ваша структура данных выглядит нормально.

Ответ №2:

Предполагая, что вы не вносите изменений в данные (добавляете больше просмотров и т.д.), Почему бы не поместить все в один большой массив? Суть ArrayLists в том, что вы можете увеличивать и сжимать их, что вам здесь не нужно. Вы можете написать методы доступа, чтобы получить нужную ячейку для заданного вида, поворота и т.д.

Использование массивов массивов — лучшая идея, таким образом, система выясняет, как получить доступ к чему для вас, и это так же быстро, как и к одному массиву.

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

Если вы хотите максимально придерживаться текущего подхода, вы можете свести к минимуму объем памяти, используемой вашими списками массивов, установив их емкость равной количеству элементов, которые они содержат. В противном случае они оставляют несколько слотов в резерве, ожидая, что вы добавите еще.

Ответ №3:

Для загрузки данных:

DataInputStream должен работать хорошо. Но убедитесь, что вы обернули базовый FileInputStream в BufferedInputStream, иначе вы рискуете выполнять операции ввода-вывода для каждого float, что может снизить производительность.

Несколько вариантов хранения данных:

  • (Очень незначительно) наиболее экономичным с точки зрения памяти способом будет хранить весь массив в формате on large float[] и вычислять в нем смещения по мере необходимости. Немного некрасиво в использовании, но может иметь смысл, если вы выполняете много вычислений или циклов обработки по всему набору.
  • Наиболее «ООП»-способом было бы иметь отдельные объекты для поворота, представления, строки и ячейки. Но использование каждой ячейки в качестве отдельного объекта довольно расточительно, может даже увеличить ваши ограничения по памяти.
  • Вы могли бы использовать вложенные списки массивов с плавающей точкой[1344] для представления данных самого низкого уровня для ячеек в каждой строке. Я понимаю, что это то, что вы сейчас делаете — на самом деле, я думаю, что это довольно хороший выбор. Накладные расходы на ArrayLists не будут значительными по сравнению с общим размером данных.
  • Последним вариантом было бы использовать значение с плавающей запятой[rotationNum][rowNum] [cellNum] для представления каждого поворота. Немного эффективнее, чем списки массивов, но манипулировать массивами обычно не так приятно. Однако это кажется довольно хорошим вариантом, если, как вы говорите, размеры массива всегда будут фиксированными. Я бы, вероятно, сам выбрал этот вариант.

Ответ №4:

Есть ли у вас какие-либо особые проблемы с производительностью / использованием при вашем текущем подходе?

Единственное, что я могу предложить на основе предоставленной вами информации, это попробовать представить представление в виде float[][] строк и ячеек.

Ответ №5:

Я также думаю, что вы можете поместить всю свою структуру данных в float[][][] (так же, как предлагает Натан Хьюз). У вас мог бы быть метод, который считывает ваш файл и возвращает float[][][] , где первое измерение соответствует представлениям (960), второе — строкам (16), а третье — ячейкам (1344): если эти цифры являются исправлениями, вам лучше использовать этот подход: вы экономите память, и это быстрее.

Ответ №6:

80 МБ не должно быть таким большим объемом данных, чтобы вам нужно было так сильно беспокоиться. Я бы действительно предложил:

  • создайте объекты-оболочки Java, представляющие наиболее логичную структуру / иерархию для имеющихся у вас данных;
  • так или иначе, убедитесь, что вы выполняете только фактический «необработанный» вызов ввода-вывода (например, InputStream.read () или эквивалент) каждые 16 КБ или около того данных — например, вы могли бы считывать в массив 16 КБ / 32 КБ байт, который завернут в ByteBuffer с целью извлечения значений с плавающей запятой или чего-либо еще, что вам нужно для ваших данных;
  • если у вас действительно есть проблемы с производительностью при таком подходе, попробуйте определить, а не сомневаться, в чем на самом деле заключается эта проблема с производительностью.

Ответ №7:

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