Re[6]: асинхронная сериализация
От: Evgeny.Panasyuk Россия  
Дата: 28.12.13 13:06
Оценка:
Здравствуйте, niXman, Вы писали:

X>что-то я уже запутался %)

X>сейчас, какие остались вопросы?

Мне интересна практика — кто как решал подобную задачу. Если есть интересные техники — с удовольствием послушаю.
Судя по топику — такая задача встречается редко: либо потому что размер сообщений маленький, либо текущей производительности достаточно, либо не замечается возможность оптимизации.
Самое близкое что есть из стандартных решений — XML/JSON SAX.

X>как я понял, пока что нет вариантов асинхронной сериализации без использования корутин?


Судя по всему stackful coroutines предоставляют самый удобный способ.
Альтернативы есть, но более громоздкие. Например на основе Boost.Fusion (для сериализации каких-то custom типов нужно вручную писать автомат, но когда все базовые типы есть — дерево структуры определяется элементарно) или кодогенерации (готовых решений вроде бы нет. думаю при желании можно добавить шаблоны в Thrift/Protobuf).
Re[6]: асинхронная сериализация
От: Evgeny.Panasyuk Россия  
Дата: 28.12.13 13:28
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

EP>>В принципе да, но также есть и целые числа переменной длины — чтобы знать где что находится, нужно как минимум распарсить такие числа и т.п.

PD>Тот факт, что их нужно распарсить, не отменяет возможности рассматривать их как массив байтов переменной длины, поэтому сводится к предыдущему.

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

PD>Теоретически я вообще не вижу ситуации, когда я не могу хранить все данные некоторого объекьа в мной выделенном блоке памяти. Не могу по той простой причине, что не все ли равно где байты эти хранятся, а раз все равно, то пусть они в моем блоке и хранятся. Разумеется, такой подход требует полного контроля над аллокацией памяти.

PD>Практически — это может быть совсем не всегда легко сделать, и не всегда применимо.

На C++ это как раз не так трудно реализуется — просто используется custom deleter.

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

PD>Любой набор последовательно расположенных данных всегда можно рассматривать как массив байтов переменной длины

Пример:
Есть int64 который нужно хранить в переменном количестве байт (допустим от 1 до 9 байт). И есть сырой сериализованный массив состоящий из таких целых переменной длинны.
Если десериализовать его в нормальный массив int64[], то получим O(1) доступ по индексу. Если же работать с ним как с сырым массивом (и без построения дополнительных вспомогательных структур) — то доступ по индексу становится O(N).
И это самый простой вариант. Если же есть древовидная структура с полями и массивами переменной длинны, причём на разных уровнях, да и ещё и сжатая чем-то типа кода Хаффмана — то всё становится намного труднее.
Re[7]: асинхронная сериализация
От: Pavel Dvorkin Россия  
Дата: 28.12.13 14:06
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Пример:

EP>Есть int64 который нужно хранить в переменном количестве байт (допустим от 1 до 9 байт). И есть сырой сериализованный массив состоящий из таких целых переменной длинны.
EP>Если десериализовать его в нормальный массив int64[], то получим O(1) доступ по индексу. Если же работать с ним как с сырым массивом (и без построения дополнительных вспомогательных структур) — то доступ по индексу становится O(N).

Я же вообще не предлагал сериализовать. Храни как хочешь, только в непрерывном куске. Хочешь — храни в нем нормальный int64[], хочешь — массив байтов некоего размера с упакованными int64, а за ним дополнительные вспомогательные структуры. Что хочешь, то и храни. А потом отправь этот блок памяти куда следует целиком.
With best regards
Pavel Dvorkin
Re[8]: асинхронная сериализация
От: Evgeny.Panasyuk Россия  
Дата: 28.12.13 14:25
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Я же вообще не предлагал сериализовать. Храни как хочешь, только в непрерывном куске. Хочешь — храни в нем нормальный int64[], хочешь — массив байтов некоего размера с упакованными int64, а за ним дополнительные вспомогательные структуры. Что хочешь, то и храни. А потом отправь этот блок памяти куда следует целиком.


В данном случае формат специфицирован, и там именно сериализация.
А так — да, иногда можно обойтись и zero-copy.
Re[5]: асинхронная сериализация
От: smeeld  
Дата: 28.12.13 14:52
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, uzhas, Вы писали:


EP>>>Основной фокус как раз тут.

EP>>>Вот вызвали async_write для первого чанка. Следующий async_write должен происходить из хэндлера записи.

U>>Почему должен?


EP>Во-первых, порядок двух асинхронных операций не определён. Во-вторых, async_write не атомарен, и сам состоит из нескольких операций типа async_write_some, которые могут перемешиваться с async_write_some от другого async_write.

EP>Но даже если у нас есть строгий порядок асинхронных записей (допустим у нас есть очередь (переменного размера, что уже не хорошо)) — то всё равно не понятно как это будет работать:
И вообще cдался этот boost::asio? Можно серилизовать с boost::serialization или чем-то готовым вроде protobuf, в отдельных потоках
или процессах, если процессоров несколько. А ввод/вывод производить в в отдельном потоке нативным
средством асинхронного ввода/вывода ОС, обёрткой над которым является boost::asio,( в linux epoll).
Этот же поток ввода/вывода будет прозводить запуск новых агентов сериализации, и взаимодействовать с запущенными,
передавать данные с очереди, которую будут заполнять агенты. Интересно узнать причины использовани именно boost::asio.
Re[6]: асинхронная сериализация
От: Evgeny.Panasyuk Россия  
Дата: 28.12.13 15:26
Оценка:
Здравствуйте, smeeld, Вы писали:

S>И вообще cдался этот boost::asio? Можно серилизовать с boost::serialization или чем-то готовым вроде protobuf,


Вообще-то boost::asio и boost::serialization ортогональны. Более того — они прекрасно работают вместе.
При использовании Boost.Serialization/Protobuf — будут ровно те же проблемы. То есть их можно использовать в лоб, с буферами любых размеров (которые и так прекрасно пересылаются Boost.Asio), что многие и делают — но это неэффективно. Эффективней использовать буфер фиксированного размера и сериализовать по частям.

S>в отдельных потоках или процессах, если процессоров несколько. А ввод/вывод производить в в отдельном потоке нативным

S> средством асинхронного ввода/вывода ОС, обёрткой над которым является boost::asio,( в linux epoll).
S>Этот же поток ввода/вывода будет прозводить запуск новых агентов сериализации, и взаимодействовать с запущенными,
S>передавать данные с очереди, которую будут заполнять агенты.

Соединений десятки тысяч. Десятки тысяч потоков/процессов не взлетят.

S>Интересно узнать причины использовани именно boost::asio.


Asio не принципиально — подойдёт любой асинхронный/неблокирующий вывод — и везде будут ровно те же проблемы.
Re[7]: асинхронная сериализация
От: niXman Ниоткуда https://github.com/niXman
Дата: 28.12.13 16:56
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Thrift/Protobuf

EP>Boost.Serialization/Protobuf
а чо, YAS не рассматривается?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: асинхронная сериализация
От: niXman Ниоткуда https://github.com/niXman
Дата: 28.12.13 17:00
Оценка:
Здравствуйте, smeeld, Вы писали:

S>А ввод/вывод производить в в отдельном потоке нативным

S>средством асинхронного ввода/вывода ОС, обёрткой над которым является boost::asio,( в linux epoll).

ну да, можно и вовсе на Си писать =)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[7]: асинхронная сериализация
От: uzhas Ниоткуда  
Дата: 28.12.13 17:48
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Сериализация быстрее I/O — что делать когда все буферы заполнены, но ещё не отправлены? (суммарный размер буферов меньше самой структуры — мы же экономим)


тут несколько может быть стратегий: выделить еще буфера, уснуть, пока буфер не освободиться, выдать ошибку (no resources)

EP>В FIX'е какой максимальный/типичный размер сообщения?


тут мне тяжело за весь протокол ответить, в нашем сервере на практике это где-то 16K / 2K

EP>Для десериализации структуры должно быть вызвано несколько on_data, так как буфер фиксированный, а структура в него не помещается.

правильно

EP>Как процедура сериализации уйдёт в сон пока ожидает следующую on_data? Как продолжит десереализацию в правильном состоянии когда придут данные?

аналогией является SAX парсер : данные пихаются снаружи, а не он тянет их откуда-то, поэтому о сне говорить не приходится. внутри обычно машина состояний живет
Re: асинхронная сериализация
От: uzhas Ниоткуда  
Дата: 28.12.13 18:08
Оценка: +1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Но смотрю я на этот вариант и мне грустно от того, что происходит перерасход памяти Эти структуры могут занимать от пары кибибайт до нескольких мебибайт, а соединений — десятки тысяч.


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

есть еще такой вариант: если разным клиентам раздаются одинаковые данные, то проще их закешировать результат сериализации) и не делать часто одну и ту же сериализацию
Re[8]: асинхронная сериализация
От: Evgeny.Panasyuk Россия  
Дата: 28.12.13 18:15
Оценка:
Здравствуйте, niXman, Вы писали:

X>а чо, YAS не рассматривается?


Рассматривался — я давно его видел, отложился в памяти как альтернатива Boost.Serialization.
В данном случае для сериализации нужны только правильные архивы, которые в любом случае писать — что для YAS, что для Boost.Serialization. Никакие дополнительные фичи типа отслеживания указателей или сериализации полиморфных типов не нужны.
Сейчас всё ядро сериализации (без YAS/Boost.Serialization) — это in/out archive + рекурсивная сериализация Boost.Fusion Forward Sequence. На всё про всё — меньше ста строк, причём 3/4 это архивы.
Структуры определяются просто как BOOST_FUSION_DEFINE_STRUCT и уже готовы к сериализации.
Re[8]: асинхронная сериализация
От: Evgeny.Panasyuk Россия  
Дата: 28.12.13 18:27
Оценка:
Здравствуйте, uzhas, Вы писали:

EP>>Сериализация быстрее I/O — что делать когда все буферы заполнены, но ещё не отправлены? (суммарный размер буферов меньше самой структуры — мы же экономим)

U>тут несколько может быть стратегий: выделить еще буфера, уснуть, пока буфер не освободиться, выдать ошибку (no resources)

Основной вопрос в том, как организовать засыпание.

EP>>В FIX'е какой максимальный/типичный размер сообщения?

U>тут мне тяжело за весь протокол ответить, в нашем сервере на практике это где-то 16K / 2K

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

EP>>Как процедура сериализации уйдёт в сон пока ожидает следующую on_data? Как продолжит десереализацию в правильном состоянии когда придут данные?

U>аналогией является SAX парсер : данные пихаются снаружи, а не он тянет их откуда-то, поэтому о сне говорить не приходится. внутри обычно машина состояний живет

Ну да, нужна машина состояний. Вопрос в том, какими способами это машину состояний можно определить. Пока что stackful coroutine — самый удобный.
Re[2]: асинхронная сериализация
От: Evgeny.Panasyuk Россия  
Дата: 28.12.13 18:34
Оценка:
Здравствуйте, uzhas, Вы писали:

U>есть еще такой вариант: если разным клиентам раздаются одинаковые данные, то проще их закешировать результат сериализации) и не делать часто одну и ту же сериализацию


Да — это хороший вариант для отправки.
Но в этом конкретном случае не только отправка больших сообщений, но также и приём
Re[9]: асинхронная сериализация
От: niXman Ниоткуда https://github.com/niXman
Дата: 28.12.13 19:25
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В данном случае для сериализации нужны только правильные архивы, которые в любом случае писать — что для YAS, что для Boost.Serialization.
что это значит?

EP>рекурсивная сериализация Boost.Fusion Forward Sequence.

YAS это умеет искаропки.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: асинхронная сериализация
От: Pzz Россия https://github.com/alexpevzner
Дата: 28.12.13 19:57
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Собственно у меня два вопроса:

EP>1. Какие есть ещё альтернативы? Возможно есть какие-то стандартные/распространённые решения?
EP>2. Встречалась ли вам такая задача? В каком контексте? И как она была решена?

В вашем несколько сумбурном описании мне слышится, по крайней мере, две ортогональные задачи:

1. Собственно, преобразование форматов между внутренним представлением и внешним представлением.
2. Как реализовать это преобразование в условиях, когда за один прием вся древовидная структура в сокет не лезет.

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

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

Да, и учтите пожалуйста, что зачастую выгоднее потратить пару мегабайт памяти, чем изобретать хитроумные алгоритмы, позволяющие этого не делать. Объем памяти (в разумных, конечно, пределах) — гораздо более дешевый ресурс, чем производительность процессора.
Re[7]: асинхронная сериализация
От: smeeld  
Дата: 28.12.13 20:31
Оценка: -2
Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>Вообще-то boost::asio и boost::serialization ортогональны. Более того — они прекрасно работают вместе.

Да это известно. Я о том, что сериализацию можно проводить классами из boost::serialization, а вот для
организации ввода/вывода не прозрачней будет вместо boost::asio использовать, например, в линуксе нативный epoll?
Сама boost::asio, та её часть, что относится к асинхронному вводу/выводу есть обёртка над epoll в линуксе.
Понятно, что потеряется кроссплатформенность, но при использование простого api epoll проще будет реализовать
сложную логику последовательной, растянутой во времени передачи сериализованных данных частями в несколько
тысяч потоков чем эти async_read/async_write которые обязательно поведут себя неизветно как.

EP>Соединений десятки тысяч. Десятки тысяч потоков/процессов не взлетят.

Есть спасение, берём четырёхпроцовый сервак, несколко, с балансировкой между ними.
А как тогда взлетают веб сервисы? Асинхронная обработка в один поток годится только если, собственно,
обработки не много. В противном случае пускаем новый поток/процесс. Связки однопоточный nginx в frontend для распределения запросов
и многопроцессный apache для обработки запросов в backend-стандарт для hayload.

EP>Asio не принципиально — подойдёт любой асинхронный/неблокирующий вывод — и везде будут ровно те же проблемы.

Вот и я о том же, используем более предсказуемые нативные для ОС api kqueue (freebsd), epoll (linux), не знаю
что там есть по этому поводу в win.
Re[7]: асинхронная сериализация
От: smeeld  
Дата: 28.12.13 20:52
Оценка: +1 -2 :)
Здравствуйте, niXman, Вы писали:

X>ну да, можно и вовсе на Си писать =)

Тонкие, ответственные участки в проге желательно писать на
так называемом С++ без классов.
Кому как нравится.
Re[8]: асинхронная сериализация
От: niXman Ниоткуда https://github.com/niXman
Дата: 28.12.13 21:19
Оценка: +2
Здравствуйте, smeeld, Вы писали:

S>при использование простого api epoll проще будет реализовать сложную логику последовательной, растянутой во времени передачи сериализованных данных частями в несколько тысяч потоков чем эти async_read/async_write которые обязательно поведут себя неизветно как.


S>Есть спасение, берём четырёхпроцовый сервак, несколко, с балансировкой между ними.


S>Вот и я о том же, используем более предсказуемые нативные для ОС api kqueue (freebsd), epoll (linux), не знаю


S>организации ввода/вывода не прозрачней будет вместо boost::asio использовать, например, в линуксе нативный epoll?

вы либо прикалываетесь, либо троллите, либо просто глупы...

S>Сама boost::asio, та её часть, что относится к асинхронному вводу/выводу есть обёртка над epoll в линуксе.

и что? банальный 'operator new' есть обертка. его тоже лучше не юзать?

не представляю, какие вещества нужно употреблять, что писать тут такое %)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[9]: асинхронная сериализация
От: smeeld  
Дата: 28.12.13 22:09
Оценка:
Здравствуйте, niXman, Вы писали:

X>вы либо прикалываетесь, либо троллите, либо просто глупы...

Ок, можно и boost::asio-элегантно получается, если расписывать логику accept-ирования
входящих соединений классами, без С-подобных нагромождений в стиле linux kernel source code.
X>и что? банальный 'operator new' есть обертка. его тоже лучше не юзать?
Ну, new не критичен, можно и оставить.
X>не представляю, какие вещества нужно употреблять, что писать тут такое %)
Не пью, не курю, занимаюсь спортом.
Re[8]: асинхронная сериализация
От: Abyx Россия  
Дата: 28.12.13 22:26
Оценка: +1
Здравствуйте, smeeld, Вы писали:

X>>ну да, можно и вовсе на Си писать =)

S>Тонкие, ответственные участки в проге желательно писать на
S>так называемом С++ без классов.
почему *желательно*, обоснуйте.

S>Кому как нравится.

вопрос не в личных пристрастиях, а в том как получится более безопасный более поддерживаемый код.
In Zen We Trust
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.