#c# #arrays #list #protobuf-net
#c# #массивы #Список #protobuf-net
Вопрос:
У меня есть большой многомерный массив, который необходимо сохранить с помощью protobuf. В массиве может быть до 5120 * 5120 = 26 214 400 элементов. К сожалению, Protobuf не поддерживает хранение многомерных массивов.
В качестве теста я написал две функции и дополнительный класс. Класс хранит и x,y, которые указывают на местоположение внутри массива (array[x, y] ). Класс имеет «значение», которое представляет собой данные из массива [x, y]. Я использую список для хранения этих данных.
Когда я генерирую довольно небольшой массив (1024 * 1024), я получаю выходной файл размером более 169 МБ. Из моего тестирования он загружает и генерирует файл очень быстро, поэтому проблем нет. Однако размер файла огромен — мне определенно нужно сократить размер.
Это нормальный размер файла или мне нужно переосмыслить весь свой процесс? Должен ли я сжимать данные перед их сохранением (архивирование файла занимает от 169 МБ до 6 МБ)? Если да, то какой самый быстрый / простой способ заархивировать файл на C #?
Это псевдокод, основанный на моем реальном коде.
[ProtoContract]
public class Example
{
[ProtoIgnore]
public string[,] MyArray { get; set; }
[ProtoMember(0)]
private List<MultiArray> Storage { get; set; }
public void MoveToList()
{
for (int x = 0; x < MyArray.GetLength(0); x )
{
for (int y = 0; y < MyArray.GetLength(1); y )
{
Storage.Add(new MultiArray
{
_x = x,
_y = y,
value = MyArray[x, y]
});
}
}
}
public void MoveToArray()
{
MyArray = new string[1024, 1024];
for (int i = 0; i < Storage.Count; i )
{
MyArray[Storage[i].X, Storage[i].Y] = Storage[i]._value;
}
}
}
[ProtoContract]
public class MultiArray
{
[ProtoMember(0)]
public int _y { get; set; }
[ProtoMember(1)]
public int _x { get; set; }
[ProtoMember(2)]
public string _value { get; set; }
}
Примечания: значение должно быть правильным x / y массива.
Я ценю любые предложения.
Ответ №1:
Я не знаю о хранилище, но, вероятно, это неправильный способ сделать это.
То, как вы это делаете, вы создаете объект MultiArray для каждой ячейки вашего массива.
Более простым и эффективным решением было бы сделать это:
String[] Storage = new String[1024*1024];
int width = 1024
int height = 1024;
for (int x = 0; x < width; x )
{
for (int y = 0; y < height; y )
{
Storage[x*width y]=MyArray[x,y];
}
}
Комментарии:
1. Спасибо! Я поэкспериментирую с этим сегодня вечером.
Ответ №2:
В конечном счете, формат protobuf не имеет понятия о массивах более высокой размерности, чем единица.
На уровне библиотеки, поскольку вы используете protobuf-net, мы могли бы заставить библиотеку творить здесь какую-то магию, по сути, рассматривая ее как;
message Array_T {
repeated int32 dimensions;
repeated T items; // packed when possible
}
(отметим, что .proto на самом деле не поддерживает дженерики, но это не имеет большого значения на уровне библиотеки)
Однако это было бы немного неудобно с точки зрения x-plat.
Но чтобы проверить, поможет ли это, вы могли бы линеаризовать свой 2D-массив и посмотреть, какое место он занимает.
В вашем случае я подозреваю, что реальная проблема (изменение размера) заключается в количестве строк. Protobuf записывает содержимое строки каждый раз, без каких-либо попыток в таблицах поиска. Возможно, также стоит проверить, какова общая длина строки sunlm (в байтах UTF-8) для содержимого вашего массива.