Здравствуйте, CoderMonkey, Вы писали:
V>>При большом кол-ве задействованных типов и малом кол-ве данных инфа о типах занимает приличное место. CM>Неа. Я на большом количестве данных сравнивал.
Информация о типах там у каждого инстанса. Это следствие того, что BF может сериализовать почти любой, в том числе и заранее неизвестный обьект. А это критично, так как BF был сделан для ремоутинга и в первую очередь для ремоутинга на границе домена.
XmlSerializer же требует статическую разметку всех используемых типов заранее, а все сериализуемые поля должны быть публично доступны, и предназначен он для парсинга и генерации XML. Поэтому там нет информации о типах, а код сериализатора можно сгенерировать перед сериализацией, тем самым обойдясь без рефлекшена.
Абсолютно разные вещи, решающие разные задачи. Сравнивать их глупо.
Здравствуйте, Ikemefula, Вы писали:
I>По уму, надо бы положить BinaryFormatter в неймспейс Debug и назвать ObjectGraphDump. Тогда многие вопросы снялись бы сами собой.
Он и так назван Formatter, а не Serializer. Но, как видишь, не останавливает.
Здравствуйте, Ikemefula, Вы писали:
НС>>Он и так назван Formatter, а не Serializer. Но, как видишь, не останавливает. I> I>formatter это слишком общее слово.
О да, главная проблема в том что слово не такое, а не в том что некоторые документацию не читают.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Информация о типах там у каждого инстанса.
Ну а сохранять информацию о каждом уникальном типе один раз и потом ссылаться на нее никак нельзя было Видимо, ручки не дотянутся так далеко из того места, откуда они растут.
, если что непонятно спрашивай
_>>- адреса объектов (в памяти), их размер, зависят от архитектуры проца (x86/x64) _>>- в случае CLR, в процессе сериализации адрес объекта может быть изменен (при дефрагментации кучи, в которой на данный момент "живет" объект)
CM>И эти проблемы тебе в любом случае неминуемо придется решать, если уж нужно писать сериализатор.
Если не придумывать проблемы на пустом месте, то и решать их не придется. В BinaryFormatter этих проблем нет.
Здравствуйте, CoderMonkey, Вы писали:
НС>>Информация о типах там у каждого инстанса.
CM>Ну а сохранять информацию о каждом уникальном типе один раз и потом ссылаться на нее никак нельзя было
Так и происходит
CM>Видимо, ручки не дотянутся так далеко из того места, откуда они растут.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, Ikemefula, Вы писали:
I>>По уму, надо бы положить BinaryFormatter в неймспейс Debug и назвать ObjectGraphDump. Тогда многие вопросы снялись бы сами собой.
НС>Он и так назван Formatter, а не Serializer. Но, как видишь, не останавливает.
Здравствуйте, Ikemefula, Вы писали:
НС>>О да, главная проблема в том что слово не такое, а не в том что некоторые документацию не читают. I>Именно потому, что документацию не читают и надо подбирать правильные имена и неймспеймы, открывать или закрывать доступ.
Увы, мир не идеален. Правильными названиями вообще мало кто заморачивается, за редким исключением типа такого.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>А если в графе циклы? Как смещение предвычислить?
1. Делаем обход графа возможных типов, генерим код для обхода объектов. Если какие типы заранее неизвестны — там уж придется использовать рефлекшен.
2. Обходим граф объектов, складываем объекты в список в порядке обнаружения
3. Идем по списку, пишем объекты
Здравствуйте, CoderMonkey, Вы писали:
CM>Оказывается, BinaryFormatter в .NET не только на порядок медленнее XmlSerializer, но и выдает результат на порядок больше по объему.
BinaryFormatter — это, скорее, инфраструктура.
Плюс некая дефолтная реализация для всех типов.
Ты можешь для конкретных типов зарегистрировать собственные форматтеры.
Плюсы бинарного форматтера вылезают, когда надо сериализовать глубокую иерархию, где экземпляры одних и тех же объектов встречаются многократно, а так же многократно ссылаются (прямо или косвенно) друг на друга. В этом месте XML-сериализация становится страшной. ))
Здравствуйте, vdimas, Вы писали:
V>Плюсы бинарного форматтера вылезают, когда надо сериализовать глубокую иерархию, где экземпляры одних и тех же объектов встречаются многократно, а так же многократно ссылаются (прямо или косвенно) друг на друга. В этом месте XML-сериализация становится страшной. ))
Ну да. Но, блин, как можно было так изгадить скорость и объем результата?
Здравствуйте, CoderMonkey, Вы писали:
CM>Ну да. Но, блин, как можно было так изгадить скорость и объем результата?
Плохая реализация портит хорошие идеи. Точно так Win Mobile 10 зафейлили, точно так .Net-песочницу зафейлили... А ведь могли бы сделать магазин обычных .Net приложений.
Здравствуйте, CoderMonkey, Вы писали:
CM>Оказывается, BinaryFormatter в .NET не только на порядок медленнее XmlSerializer, но и выдает результат на порядок больше по объему.
Талант нужен. protobuf на жээсе порвёт в хлам и бинари, и xml дотнетные.
Здравствуйте, vdimas, Вы писали:
V>BinaryFormatter — это, скорее, инфраструктура. V>Плюс некая дефолтная реализация для всех типов. V>Ты можешь для конкретных типов зарегистрировать собственные форматтеры.
V>Плюсы бинарного форматтера вылезают, когда надо сериализовать глубокую иерархию, где экземпляры одних и тех же объектов встречаются многократно, а так же многократно ссылаются (прямо или косвенно) друг на друга. В этом месте XML-сериализация становится страшной. ))
Здравствуйте, CoderMonkey, Вы писали:
V>>Плюсы бинарного форматтера вылезают, когда надо сериализовать глубокую иерархию, где экземпляры одних и тех же объектов встречаются многократно, а так же многократно ссылаются (прямо или косвенно) друг на друга. В этом месте XML-сериализация становится страшной. ))
CM>Ну да. Но, блин, как можно было так изгадить скорость и объем результата?
В первых версиях у них был такой фокус, OnDeserializationCallback. У него была квадратичная сложность выполнения
Здравствуйте, CoderMonkey, Вы писали:
V>>Плюсы бинарного форматтера вылезают, когда надо сериализовать глубокую иерархию, где экземпляры одних и тех же объектов встречаются многократно, а так же многократно ссылаются (прямо или косвенно) друг на друга. В этом месте XML-сериализация становится страшной. ))
CM>Ну да. Но, блин, как можно было так изгадить скорость и объем результата?
Это смотря как сериализовать в XML и каков объем строк там.
В UTF-8 строки обычно короче.
В XML-сериализации часто целевой тип подаётся извне в коде сериализации-десериализации, в бинарной инфа о типах хранится вместе с данными.
При большом кол-ве задействованных типов и малом кол-ве данных инфа о типах занимает приличное место.
Здравствуйте, Ikemefula, Вы писали: I>Талант нужен. protobuf на жээсе порвёт в хлам и бинари, и xml дотнетные.
Как будто protobuf-а под .net нету Прикрутить можно любой, BinaryFormatter просто один из многих...
Здравствуйте, QrystaL, Вы писали:
QL>Здравствуйте, Ikemefula, Вы писали: I>>Талант нужен. protobuf на жээсе порвёт в хлам и бинари, и xml дотнетные. QL>Как будто protobuf-а под .net нету
Я курсе. Это отменяет проблемы бинариформаттера?
>Прикрутить можно любой, BinaryFormatter просто один из многих...
Сравнение с жээс показывает, что бинариформаттер тормозной хлам, убогий и никому не нужный. Сколько помню, никто им не пользовался, все писали свои форматтеры, пока не появились вещи навроде протобуфа.
В принципе в дотнете слишком много вещей такого вот качества, как этот бинариформаттер.
Здравствуйте, Ikemefula, Вы писали:
I>В первых версиях у них был такой фокус, OnDeserializationCallback. У него была квадратичная сложность выполнения
Ну, это был косяк в реализации MultiCast-делегатов (кто еще помнит что это значит ), к де/сериализации отношение имеет опосредованное, но да, при десериализации большого графа объектов было весело, я помню твои посты и как лазил в натив ротора..
Здравствуйте, pilgrim_, Вы писали:
_>Так и происходит
[Serializable]
class TestClass
{
public TestClass(int data)
{
Data = data;
Data2 = data;
Time = DateTime.UtcNow;
}
public readonly DateTime Time;
public int Data;
public double Data2;
public override string ToString()
{
return $"{Time} {Data}";
}
}
class Program
{
static void Main(string[] args)
{
var data = new List<TestClass>();
for (var i = 0; i < 1000_000; i++)
{
data.Add(new TestClass(i));
}
using (var stream = new MemoryStream())
{
var watch = Stopwatch.StartNew();
var writer = new BinaryFormatter();
writer.Serialize(stream, data);
watch.Stop();
var size = stream.Position;
Console.WriteLine($"{size:n0}\t{watch.Elapsed.TotalSeconds}");
}
Debugger.Break();
}
}
34,000,425 1.975343
4+8+8 байт = 20
Откуда еще 14 байт на каждый объект?
Здравствуйте, CoderMonkey, Вы писали:
CM>4+8+8 байт = 20 CM>Откуда еще 14 байт на каждый объект?
На объект может быть ссылка? может, соотв. чтобы кто-то на кого-то мог ссылаться, этот "кого-то" должен иметь идентификатор, а тот кто ссылается должен хранить ссылку на этого "кого-то".
в твоем случае на объекты TestClass ссылается List, в цифрах для твоего графа (List/TestClass) на каждый новый инстанс TestClass в списке получается 14 байт:
Здравствуйте, pilgrim_, Вы писали:
I>>В первых версиях у них был такой фокус, OnDeserializationCallback. У него была квадратичная сложность выполнения
_>Ну, это был косяк в реализации MultiCast-делегатов (кто еще помнит что это значит ), к де/сериализации отношение имеет опосредованное, но да, при десериализации большого графа объектов было весело, я помню твои посты и как лазил в натив ротора..
По уму, надо бы положить BinaryFormatter в неймспейс Debug и назвать ObjectGraphDump. Тогда многие вопросы снялись бы сами собой.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Два раза обходить граф рефлекшеном?
Зачем два раза обходить? Раз обойти, второй — по сохраненному списку.
А по хорошему, надо было просто генерить код для обхода. Но ручки то не дотягиваются, видимо.
Здравствуйте, pilgrim_, Вы писали:
_>На объект может быть ссылка? может, соотв. чтобы кто-то на кого-то мог ссылаться, этот "кого-то" должен иметь идентификатор, а тот кто ссылается должен хранить ссылку на этого "кого-то".
На самом деле, конечно, не должен. Адрес объекта — это и есть его идентификатор. Да и для списка хранить ссылку на каждый элемент — странно как-то.
Здравствуйте, CoderMonkey, Вы писали:
НС>>Два раза обходить граф рефлекшеном? CM>Зачем два раза обходить? Раз обойти, второй — по сохраненному списку.
Это всер равно замедлит и сильно.
CM>А по хорошему, надо было просто генерить код для обхода.
JIT не даст работать коду, который обращается к приватным полям извне. Это во-первых. А во-вторых в случае BinaryFormatter заранее неизвестен список типов, в отличие от того же XmlSerializer.
CM> Но ручки то не дотягиваются, видимо.
BinaryFormatter это легаси, его никто существенно переделывать не будет. Ты какую задачу вообще решаешь? Зачем тебе BF понадобился?
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>>>Он и так назван Formatter, а не Serializer. Но, как видишь, не останавливает. I>> I>>formatter это слишком общее слово.
НС>О да, главная проблема в том что слово не такое, а не в том что некоторые документацию не читают.
Именно потому, что документацию не читают и надо подбирать правильные имена и неймспеймы, открывать или закрывать доступ.
Здравствуйте, CoderMonkey, Вы писали:
CM>Здравствуйте, pilgrim_, Вы писали:
_>>На объект может быть ссылка? может, соотв. чтобы кто-то на кого-то мог ссылаться, этот "кого-то" должен иметь идентификатор, а тот кто ссылается должен хранить ссылку на этого "кого-то".
CM>На самом деле, конечно, не должен. Адрес объекта — это и есть его идентификатор.
Сюр какой-то, какой адрес объекта в сериализованном представлении, в файле например?
CM>Да и для списка хранить ссылку на каждый элемент — странно как-то.
А что он должен хранить? Как ссылаться на произвольный сериализуемый объект (в файле напр.)?
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Это всер равно замедлит и сильно.
С фига ли, позвольте узнать? И наколько сильно?
НС>JIT не даст работать коду, который обращается к приватным полям извне. Это во-первых. А во-вторых в случае BinaryFormatter заранее неизвестен список типов, в отличие от того же XmlSerializer.
1. Есть unsafe, или его уже отменили?
2. Это нисколько не мешает сгенерить код для известных типов
НС>BinaryFormatter это легаси, его никто существенно переделывать не будет. Ты какую задачу вообще решаешь? Зачем тебе BF понадобился?
Какую решаю — уже решил. Просто решил поиграться и удивился, насколько он феноменально крив.
А ты, кстати, какую задачу здесь решаешь?
Здравствуйте, CoderMonkey, Вы писали:
НС>>JIT не даст работать коду, который обращается к приватным полям извне. Это во-первых. А во-вторых в случае BinaryFormatter заранее неизвестен список типов, в отличие от того же XmlSerializer.
CM>1. Есть unsafe, или его уже отменили?
Работает только для full trust
CM>2. Это нисколько не мешает сгенерить код для известных типов
Нк попробуй, сгенери код чтения или записи приватного поля, а потом попробуй выполнить. И да, для BF никаких известных типов кроме примитивов не существует в принципе.
НС>>BinaryFormatter это легаси, его никто существенно переделывать не будет. Ты какую задачу вообще решаешь? Зачем тебе BF понадобился? CM>Какую решаю — уже решил. Просто решил поиграться и удивился, насколько он феноменально крив.
Он не крив, просто ты явно применил его не по назначению.
CM>А ты, кстати, какую задачу здесь решаешь?
Здравствуйте, CoderMonkey, Вы писали:
CM>Можно подумать, он и так не требует full trust
Не требует. Иначе бы междоменное взаимодействие без full trust не работало.
НС>>И да, для BF никаких известных типов кроме примитивов не существует в принципе. CM>С чего бы?
Здравствуйте, CoderMonkey, Вы писали:
CM>Здравствуйте, pilgrim_, Вы писали:
_>>Сюр какой-то, какой адрес объекта в сериализованном представлении, в файле например?
CM>И в чем заключается "сюр"?
Так не делают
— адреса объектов (в памяти), их размер, зависят от архитектуры проца (x86/x64)
— в случае CLR, в процессе сериализации адрес объекта может быть изменен (при дефрагментации кучи, в которой на данный момент "живет" объект)
_>>А что он должен хранить? Как ссылаться на произвольный сериализуемый объект (в файле напр.)?
CM>Достаточно хранить просто тела объектов.
— BinaryFormatter спецом сделан, и тебе уже сказали об этом, для возможности передать полный граф объектов по ремотингу, AppDomain/сеть, с возможностью полностью воссоздать (десериализовать) оригинальный граф
— в общем случае это дороже в плане объема, чем хранить ссылку (конечно возможны и оптимизации — если объем хранения id+ссылки > тела объекта, тело сохранять выгоднее, т.е. можно хранение сделать вариативным), но это не про BinaryFormatter, см. п.1
-при циклических ссылках (напр. parent/child+parent) сохранение "сырого" тела невозможно, попробуй это сделать с пом. XmlSerializer
CM>А нафига тебе понадобилось ссылаться на произвольный сериализуемый объект?
произвольный здесь в смысле любой (в товем примере List ссылается на объекты TestClass)
Здравствуйте, pilgrim_, Вы писали:
_>Так не делают
Еще один с "гениальными" объяснениями
_>- адреса объектов (в памяти), их размер, зависят от архитектуры проца (x86/x64) _>- в случае CLR, в процессе сериализации адрес объекта может быть изменен (при дефрагментации кучи, в которой на данный момент "живет" объект)
И эти проблемы тебе в любом случае неминуемо придется решать, если уж нужно писать сериализатор.