Создание больших файлов HDF5

#c# #.net #.net-core #memory-leaks #hdf

Вопрос:

Я должен написать код с использованием .NET 5.0 C#, который будет генерировать файлы HDF5 для каждого из следующих случаев:

  • 2D массив случайных двойников. Размер: 20M x 1K (таким образом, размер файла должен быть около 150 ГБ без сжатия)
  • 2D массив случайных строк (длина каждой строки должна составлять 30 символов). Размер: 500K x 100

В первом случае проблема, с которой я столкнулся, — это проблема с оперативной памятью. Средства диагностики Visual Studio показывают, как во время работы программы увеличивается объем частной памяти, занимаемой байтами, и я не могу понять, в чем причина этого. Вот код, который я использовал:

 using HDF.PInvoke;
using System;
using System.IO;

namespace HTFCalculation
{
    public class Program
    {
        private static uint rows = 1000;
        private static uint columns = 20000000;

        public static void Main(string[] args)
        {
            Console.WriteLine("Starting program");
            Write(GenerateRandomNumericArray(), false);
            Console.WriteLine("Program is completed");
        }

        public static unsafe void Write(double[] data, bool enableZip)
        {
            Console.WriteLine("Generating a HDF file");

            // Declaring variables.
            string filePath = Directory.GetCurrentDirectory()   "\result.h5";
            ulong[] dims = { rows, 1 };
            ulong[] maxDims = { rows, columns };
            ulong[] chunkDims = { rows, 1 };
            ulong[] size = new ulong[2];
            ulong[] offset = new ulong[2];

            // Create the data space with unlimited dimensions.
            var dataspace = H5S.create_simple(dims.Length, dims, maxDims);

            // Create a new file.If file exists its contents will be overwritten.
            long file = H5F.create(filePath, H5F.ACC_TRUNC, H5P.DEFAULT, H5P.DEFAULT);

            // Modify dataset creation properties, i.e. enable chunking.
            long cparms = H5P.create(H5P.DATASET_CREATE);
            int status = H5P.set_chunk(cparms, dims.Length, chunkDims);

            // Set compressing parameter if needed.
            if (enableZip)
            {
                H5P.set_filter(cparms, H5Z.filter_t.DEFLATE, 0, new IntPtr(1), new uint[] { 5 });
            }

            // Create a new dataset within the file using cparms creation properties.
            long dataset = H5D.create(file, "data", H5T.NATIVE_DOUBLE, dataspace, 0, cparms, 0);

            // Extend the dataset. This call assures that dataset is at least 1 x column count.
            size[0] = rows;
            size[1] = 1;
            status = H5D.set_extent(dataset, size);

            // Select a hyperslab.
            long filespace = H5D.get_space(dataset);
            offset[0] = 0;
            offset[1] = 0;
            status = H5S.select_hyperslab(filespace, H5S.seloper_t.SET, offset, null, dims, null);

            // Write the data to the hyperslab.
            fixed (double* dataPtr = data)
            {
                status = H5D.write(dataset, H5T.NATIVE_DOUBLE, dataspace, filespace, H5P.DEFAULT, new IntPtr(dataPtr));
            }


            for (int i = 1; i < columns; i  )
            {
                // Extend the dataset. Adding row.
                size[1]  ;
                status = H5D.set_extent(dataset, size);

                // Select a hyperslab. Increasing row offset.
                filespace = H5D.get_space(dataset);
                offset[1]  ;
                status = H5S.select_hyperslab(filespace, H5S.seloper_t.SET, offset, null, dims, null);

                // Write the data to the hyperslab.
                fixed (double* dataPtr = data)
                {
                    status = H5D.write(dataset, H5T.NATIVE_DOUBLE, dataspace, filespace, H5P.DEFAULT, new IntPtr(dataPtr));
                }
            }

            // Close/release resources.
            H5D.close(dataset);
            H5S.close(dataspace);
            H5S.close(filespace);
            H5F.close(file);

            Console.WriteLine("HDF file is generated");
        }

        public static double[] GenerateRandomNumericArray()
        {
            Console.WriteLine("Preparing data array");
            Random rnd = new();
            double[] result = new double[rows];
            for (int i = 0; i < rows; i  )
            {
                result[i] = rnd.NextDouble();
            }

            Console.WriteLine("Array is readyn");

            return resu<
        }
    }
}
 

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

Другой вопрос заключается в том, как записать массив 2D-строк (длиной 30 символов) в файл HDF5? H5D.write() метод требует IntPrt в качестве последнего параметра, поэтому я не нашел никакого способа сделать это.

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

Заранее благодарю вас!