вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 18.08.04 07:11
Оценка:
Уважаемый Олл,

С .net я только начинаю знакомиться, но с сериализацией я знаком давно
по MFC. И там еще у меня возник вопрос, на который я ответа не нашел.
Предполагаю, что и здесь его нет, но все же, может, кто-то скажет
интересное.
Для понятности задачу слегка упростил. В действительности все было
намного сложнее.

Есть класс — двумерная матрица. Матрица сильно разрежена. Ее надо
сохранить, но нули сохранять не надо.

Для сохранения предлагется простейший формат

Целое N3 — число троек.
Первая тройка — i,j, value
Вторая тройка — i,j, value
И т.д.

Насколько я понимаю, здесь надо сериализоваться с написанием собственной
ISerializable.GetObjectData
и специального конструктора. Хорошо.

Проблема же вот в чем. Я не знаю N3. Я его узнаю, только когда
просканирую матрицу и подсчитаю число ненулевых элементов. А вывести его
надо сначала, иначе потом я не при десериализации не буду знать, сколько
троек читать.

(Конечно, есть вариант с записью в конец ограничителя — чего-то вроде
(0,0,0). Здесь он проходит, но, напоминаю, исходная задача была намного
сложнее. Так что этот вариант не рассматривается).

Получается, что алгоритм двухпроходной. На первом проходе находим N3, на
втором — записываем тройки.

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

Можно ли сделать алгоритм однопроходным при сериализации ?

--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re: вопрос по сериализации
От: Holmes Россия  
Дата: 18.08.04 07:20
Оценка:
Pavel,

А как насчет варианта заранее иметь количество заполненных ячеек в матрице?

Удачи, Сергей.
Re[2]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 18.08.04 07:33
Оценка:
Привет!

Holmes wrote:
>
> Pavel,
>
> А как насчет варианта заранее иметь количество заполненных ячеек в матрице?

Согласен, в данном случае это возможно, но , напоминаю, исходная задача
была намного сложнее. Если хочешь, немного деталей. Матрица была
трехмерной, и вертикали в ней состояли из ненулевых кусков, вот эти
куски надо было и выводить, причем при выводе анализировалось, не был ли
такой же кусок (т.е того же размера и с такими же значениями) выведен
раньше в другой вертикали, и если да — он не выводился, а делалась
ссылка на его позицию в файле. Это все несколько минут занимало . Что
поделать, размер матрицы был огромный (порядка 5000*5000*200) и в ОП она
никогда целиком не хранилась.


--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re: вопрос по сериализации
От: Apollo13 Украина  
Дата: 18.08.04 07:52
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>Если бы вместо сериализации я просто в файл писал — алгоритм

PD>однопроходной. Пропускаем в файле 4 байта для N3, записываем тройки
PD>(одновременно считаем N3) , позиционируемся назад к позиции N3,
PD>записываем ее.

Как насчет во время сериализации записать все что нужно в ArrayList и сериализовать его?
Re[2]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 18.08.04 08:07
Оценка:
Привет!

Apollo13 wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
>
> PD>Если бы вместо сериализации я просто в файл писал — алгоритм
> PD>однопроходной. Пропускаем в файле 4 байта для N3, записываем тройки
> PD>(одновременно считаем N3) , позиционируемся назад к позиции N3,
> PD>записываем ее.
>
> Как насчет во время сериализации записать все что нужно в ArrayList и сериализовать его?

Ох нет, только не это . Там десятки, если не сотни Мб. См. пояснение
в моем ответе Holmes

--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[3]: вопрос по сериализации
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.08.04 09:09
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Матрица была

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

Мне кажется при таком расскладе самым разумным было бы сделать хэш-таблицу хранящую ссылки на элементы матрицы (индекс или еще что), так как иначе время поиска дубликата будет слишком велико. Ну, и потом серализовать эту хэш-таблицу.

PD> Это все несколько минут занимало . Что

PD>поделать, размер матрицы был огромный (порядка 5000*5000*200) и в ОП она
PD>никогда целиком не хранилась.

А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 18.08.04 09:30
Оценка:
Привет!

VladD2 wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:

<skipped>

> А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же.


Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и
выводить. Не это меня интересует, а другое.

Можно ли при сериализации с собственной реализацией GetObjectData
передвигаться в потоке ? Т.е. оставить место , а потом к нему вернуться
и записать значение. Например

Оставить место для A
Вывести B
Вывести C
Вывести D
Вернуться и записать A
Вернуться в позицию после D

В общем, аналогично FileStream.Position

--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[5]: вопрос по сериализации
От: VladD2 Российская Империя www.nemerle.org
Дата: 18.08.04 12:42
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и

PD>выводить. Не это меня интересует, а другое.

Дык именно неверное представление в первую очередь бросается в глаза.

PD>Можно ли при сериализации с собственной реализацией GetObjectData

PD>передвигаться в потоке ? Т.е. оставить место , а потом к нему вернуться
PD>и записать значение.

Ты волен создать свой поток и делать с ним что душа пожелает. Бинари- и Соап-форматер принимают именованные значения через SerializationInfo.AddValue(). Подсунь туда свой массив байтов или стрим.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: вопрос по сериализации
От: Lloyd Россия  
Дата: 18.08.04 12:50
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

А почему бы просто не писать в MemoryStream. А после просто вызвать метод GetBuffer и получить все что ты туда записал в виде массива байт.
Re: вопрос по сериализации
От: Poudy Россия  
Дата: 18.08.04 16:46
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD> ...[skipped]...


PD>Есть класс — двумерная матрица. Матрица сильно разрежена. Ее надо

PD>сохранить, но нули сохранять не надо.

PD>Насколько я понимаю, здесь надо сериализоваться с написанием собственной

PD>ISerializable.GetObjectData
PD> и специального конструктора. Хорошо.
При сериализации в Net в поток пишешь не ты. Собственно... порядок параметров не важен.

Сделай так:

ArrayList rowsList = new ArrayList(/*~N*/);
.... // добавление троек.

int[][] rows = rowsList.ToArray(typeof(int[])) as int[][];
или
int[,] rows = ....

info.AddValue("rows", rows);

ну а N, вообще говоря, теперь и не нужно никуда писать.
Re[6]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 19.08.04 05:14
Оценка:
Привет!

VladD2 wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
>
> PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и
> PD>выводить. Не это меня интересует, а другое.
>
> Дык именно неверное представление в первую очередь бросается в глаза.

Ну и бог с ним . Я ведь не об этом спрашиваю, а о сериализации.

>

> PD>Можно ли при сериализации с собственной реализацией GetObjectData
> PD>передвигаться в потоке ? Т.е. оставить место , а потом к нему вернуться
> PD>и записать значение.
>
> Ты волен создать свой поток и делать с ним что душа пожелает. Бинари- и Соап-форматер принимают именованные значения через SerializationInfo.AddValue(). Подсунь туда свой массив байтов или стрим.

А вот здесь, если можно, поподробнее. Мне самому вчера эта мысль в
голову пришла. Идея следующая

Открываем свой поток
Класс имплементирует ISerializable
В GetObjectData делаю следующее
AddValue(произвольное целое)
Position1 = Stream.Position // запомнили позицию
Теперь в цикле прохожу матрицу и заношу по AddValue все тройки и считаю
их количество — N3
Position2 = Stream.Position // запомнили позицию
Stream.Position = Position1
AddValue(N3) // записали вместо произвольного целого N3
Stream.Position = Position2 // и вернулись в конец

Это корректно ?


--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[2]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 19.08.04 05:22
Оценка:
Привет!

Lloyd wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
>
> А почему бы просто не писать в MemoryStream. А после просто вызвать метод GetBuffer и получить все что ты туда записал в виде массива байт.

Не совсем понял. MemoryStream, как я понимаю, находится в ОП, так ? Т.е.
ты предлагаешь сначала туда записать, а потом взять байты и их
сериализовать ? Это решение не пройдет — объем данных ОЧЕНЬ большой и
НИКАКОЕ копирование их по ходу сериализации просто недопустимо.
Я понимаю (даже с моим знанием .net , что можно придумать еще много
других решений. Вообще, если этот вопрос рассматривать чисто
практически, то разумное решение находится за 1 минуту — выкинуть это N3
вообще, а в конце записать тройку (0,0,0) . Мой вопрос в другом —
можно ли перемещаться по потоку при сериализации ? Иными словами ,
сериализация — строго последовательный алгоритм или все же можно в нем
позиционироваться ?
См. также мой ответ VladD2

--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[2]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 19.08.04 05:24
Оценка:
Привет!

Poudy wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
>
> PD> ...[skipped]...
>
> PD>Есть класс — двумерная матрица. Матрица сильно разрежена. Ее надо
> PD>сохранить, но нули сохранять не надо.
>
> PD>Насколько я понимаю, здесь надо сериализоваться с написанием собственной
> PD>ISerializable.GetObjectData
> PD> и специального конструктора. Хорошо.
> При сериализации в Net в поток пишешь не ты. Собственно... порядок параметров не важен.
>
> Сделай так:
>
> ArrayList rowsList = new ArrayList(/*~N*/);
> .... // добавление троек.

Никакое копирование при сериализации недопустимо по причине ограничений
по памяти. См. также мои другие сегодняшние ответы.


--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[5]: вопрос по сериализации
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.08.04 08:43
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

>> А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же.


PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и

PD>выводить.

Потому что проблема именно в этом.

PD>Можно ли при сериализации с собственной реализацией GetObjectData

PD>передвигаться в потоке ?

Нет, потому что не любой поток допускает позиционирование.
... << RSDN@Home 1.1.4 beta 2 rev. 162>>
AVK Blog
Re[6]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 19.08.04 08:51
Оценка:
Привет!

AndrewVK wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:
>
> >> А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же.
>
> PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и
> PD>выводить.
>
> Потому что проблема именно в этом.
>
> PD>Можно ли при сериализации с собственной реализацией GetObjectData
> PD>передвигаться в потоке ?
>
> Нет, потому что не любой поток допускает позиционирование.

А если в GetObjectData проверять контекст и разрешать, только если это
File ?

--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[7]: вопрос по сериализации
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.08.04 09:25
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А если в GetObjectData проверять контекст и разрешать, только если это

PD>File ?

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

P.S. И сокращай лишнее цитирование.
... << RSDN@Home 1.1.4 beta 2 rev. 162>>
AVK Blog
Re[8]: вопрос по сериализации
От: Pavel Dvorkin Россия  
Дата: 19.08.04 09:28
Оценка:
Привет!

AndrewVK wrote:
>
> Здравствуйте, Pavel Dvorkin, Вы писали:

> Боюсь механика кастомной сериализации универсальная и на подобные извращения не рассчитана. Вобщем тебе правильно тут советуют — либо храни свою матрицу ввиде хешей (а для разреженной матрицы именно этот способ хранения является оптимальным), либо формируй список вершин со значениями в памяти целиком.


Понятно. Все это не проходит, так как матрица была взята только для
пояснения сути проблемы, реальную проблему я описал в одном из ответов.
Ну что же, раз нельзя, значит, нельзя.
--
With best regards,
Pavel Dvorkin
Posted via RSDN NNTP Server 1.7 "Bedlam"
With best regards
Pavel Dvorkin
Re[7]: вопрос по сериализации
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.04 11:08
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Это корректно ?


Просто сохрани нужное тебе число с отдельным именем. А с другим именем сохрани ссылку на стрим. Когда будешь читать, то читай и то и другое, а потом уже читай свой стрим.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: вопрос по сериализации
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.04 11:08
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Нет, потому что не любой поток допускает позиционирование.


Да нет поблем сохранить нужную величину под отдельным именем. И по стримам прыгать не прицдется.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: вопрос по сериализации
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.04 11:08
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

Ты бы цитаты вырезал. А то очень неудобно читать одну строчку. Скролировать больше приходится. Да и БД не резиновая.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: вопрос по сериализации
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.04 11:08
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Не совсем понял. MemoryStream, как я понимаю, находится в ОП, так ? Т.е.

PD>ты предлагаешь сначала туда записать, а потом взять байты и их
PD>сериализовать ? Это решение не пройдет — объем данных ОЧЕНЬ большой и
PD>НИКАКОЕ копирование их по ходу сериализации просто недопустимо.

Думаю ты преувеличивашь проблему. Объем данных будет значительно меньше твоей матрицы. К тму же есть своп. Если что ОС займет место в нем.

В конце концов сегда вместоа стрима можно использовать дисковый файл и стрин на его основе.

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

И помни, сериализация в дотнете очень не эффективная. Если ты создашь свой стрим, то резко повысишь производительность и понизишь расход памяти. Так что...

Кстати, зачем тебе сериализация? Для каки целей?

PD>Я понимаю (даже с моим знанием .net , что можно придумать еще много

PD>других решений. Вообще, если этот вопрос рассматривать чисто
PD>практически, то разумное решение находится за 1 минуту — выкинуть это N3
PD>вообще, а в конце записать тройку (0,0,0) .

Во-во. И тормоза с перерасходм памяти выростят на порядок, так как стандартная сериализация дико не эффективна.

PD> Мой вопрос в другом -

PD>можно ли перемещаться по потоку при сериализации ?

Зависит от потока. Стандартная сериализация вообще не предоставляет тебе никаких потоков. Она предлагает создать тебе граф обхектов или заполнить словарь (имя->значение). Сериализация же при этом делается дотнетом (системными библиотеками). Нужно это для двух вещей. 1. Это позволяет решить проблему чтения сериализованной информации другой версии. 2. Это позволяет абстрагироваться от формата сериализации и, например, сохраняь данные в ХМЛ. Но это довольно не эффективно, плюс ко всему, орлы из МС реализовали этот механизм из рук вон плохо. Так что лучше сериализовать вручную, в тот самый мемори-стрим (или файл). А потом или просто использовать этот стрим, или подсовывать его стандартному сериализатору.

PD> Иными словами ,

PD>сериализация — строго последовательный алгоритм или все же можно в нем
PD>позиционироваться ?

Ни то, ни то. Ответ выше.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: вопрос по сериализации
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 19.08.04 14:05
Оценка:
Здравствуйте, VladD2, Вы писали:

AVK>>Нет, потому что не любой поток допускает позиционирование.


VD>Да нет поблем сохранить нужную величину под отдельным именем. И по стримам прыгать не прицдется.


Ты не понял — он хочет в стрим сначала записать количество, потом данные, притом количество он заранее не знает, а держать все данные в памяти или делать два прохода не хочет.
... << RSDN@Home 1.1.4 beta 2 rev. 162>>
AVK Blog
Re[8]: вопрос по сериализации
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.04 16:28
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Ты не понял — он хочет в стрим сначала записать количество, потом данные, притом количество он заранее не знает, а держать все данные в памяти или делать два прохода не хочет.


Я все понял. Но как ты понимашь стримов там просто нет. Так что его один фиг вручную создавать. А если так, то количество можно хранить и под отдельным именем.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: вопрос по сериализации
От: mihailik Украина  
Дата: 21.08.04 21:40
Оценка:
PD>Ох нет, только не это . Там десятки, если не сотни Мб. См. пояснение
PD>в моем ответе Holmes

1. Так ведь десятки разреженных мегабайт?
2. Сериализация в дотнете работает очень небыстро. При сериализации нет доступа к бинарному виду, все виртуализировано до уровня именованых свойств.



Если ты хочешь в бинарном виде сохранять, делай так.
* Создай MemoryStream, в конструкторе задай примерную вместимость (прикинь, какой процент ячеек обычно заполнен, добавь чуток сверху).
* Беги по матрице, сбрасывай понемногу данные.
* Получи MemoryStream.ToArray и скинь его сериализационному механизму в один именованый слот.
* Скинь размер в другой именованый слот.
Re[3]: вопрос по сериализации
От: Poudy Россия  
Дата: 22.08.04 08:28
Оценка:
Тогда это уже.., простите,. .. не NET сериализация.
Re[3]: вопрос по сериализации
От: mihailik Украина  
Дата: 22.08.04 10:07
Оценка:
PD>Если хочешь, немного деталей. Матрица была
PD>трехмерной, и вертикали в ней состояли

Тогда действительно лучшим решением будет создать правильное хранилище для этой матрицы (которое используется в Run-Time), и потом сериализовать его стандартным образом, вообще без custom ISerializable implementation.

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

И реализовывать механизм Copy-On-Write. При попытке изменения данных в объекте-столбце, смотреть на то, используетя ли он "в нескольких позициях". Если да, то делать копию, и уменьшать счетчик. То есть при возникновении изменений совместно используемый столбец будет "расслаиваться", дивергенция.

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



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

Такое бережливое отношение к памяти ускорит и runtime-обработку, так как скорость перезагрузки процессорных кешей обычно очень критична для обсчетов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.