LINUX.ORG.RU

Распарсить json по мере поступления данных

 ,


0

3

Хочется иметь стандартный интерфейс для выделения обьектов из потока вида:

data = socket.read(1024)
parser.feed(data)
objects = parser.get_objects()
for o in objects:
    process_object(o)

Есть ли такая возможность в стандартном json модуле питона? Я что-то сходу не нашёл.

TL;DR: нет в стандартной библиотеке, такой возможности нет, максимум, можно откусить от строки кусок, с помощью JSONDecoder.raw_decode, но докормить парсер в случае если в первый раз пришла только половина документа, возможности нет.

Сторонние реализации гугляться по запросу python json stream.

★★★★★

Последнее исправление: pon4ik (всего исправлений: 2)

Ответ на: комментарий от dzidzitop

Ну об чём и речь - у тебя усё оправданно. Мне нафик не нужно, мои процессы будут спать 99.99% времени, т.к. будут относительно тупыми прокси.

Кстати, интереса для - ты вот сравнил свою поделку с jsoncpp, а не сравнивал с чем-то типа spider monkey(не уверен правда насчёт потокового режима в нём, ибо сделан он всё таки не для того, а детально я api не изучал)?

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

Не сравнивал. Сначала код был на jsoncpp, чтобы сделать всё остальное, а потом переписал работу с json.

Но поскольку у меня не парсер любого json, а парсер конкретного формата данных, выраженного в синтаксисе json, то будет лучше. Однако любой потоковый универсальный парсер будет достаточно хорош для почти всех применений. Эффективность потокового парсера сложно сильно испортить кривыми руками.

dzidzitop ★★
()
Ответ на: комментарий от pon4ik

Когда требуется лэйтенси порядка микросекунд

Расскажи это например биржам

ЕМНИП, там не так всё работает. Там уже готовая структура летает по сети которую парсить не надо. Более того, в hft некоторые решения могут приниматься вообще до того как пакет был получен целиком (если я правильно понял). Там fpga, всё такое. Могу ошибаться, говорю что помню на собеседовании с трейдерам.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

Там летает sbe или fast, у некоторых индивидов летает медленный по сравнению с первыми двумя protobuf, но решения все одного типа - есть схема описывающая сообщение, есть протокол разкодировки, так что там ещё как нужно парсить, притом очень при очень быстро и без лишних выделений памяти:). В большинстве случаев летит инфа по всему рынку. А клиенту нужна инфа по конкретным сущностям чаще всего. На fpga уже математика крутится, либо сетевой стек, в зависимости от того какой эндпоинт рассматривать, и далеко не у всех, а уж ещё меньшему количеству народа это действительно нужно.

pon4ik ★★★★★
() автор топика
Последнее исправление: pon4ik (всего исправлений: 1)
Ответ на: комментарий от true_admin

некоторые решения могут приниматься вообще до того как пакет был получен целиком

Вот именно тут, и лежит магистральный юзекейс применения sax подобных интерфейсов разбора.

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

В сетевом.

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

нормальной

Перпендикулярной чему?

Deleted
()
Ответ на: комментарий от Deleted

В сетевом

Че ета? Это не эффективно в случае самой распространенной аппаратной платформы на том же десктопе и сервере(тот же ммвб, cme и насдак вполне себе не согласны с твоим решением, но там ессно дебилы сидят, а ты у нас умница).

Но ты так и не аргументировал, зачем в протоколе, где и так можно однозначно откусить сообщение из потока, длинна сообщения?

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

не эффективно

лiл

ммвб, cme и насдак

Не стоит разносить HFT-шизу по всей индустрии.

зачем в протоколе, где и так можно однозначно откусить сообщение из потока, длинна сообщения?

Чтобы ты и другие не создавали подобные треды.

Deleted
()
Ответ на: комментарий от Deleted

Не знаю, как подобное можно было вычитать в моем сообщении

архитектор — идиот
интеграцию с идиотами
Скажи архитектору протокола, что он даун

А так да, согласен пора сворачивать :)

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

Бугога. То что Брэм дятло, которое соображает в инженерии чуть менее чем никак это всем и так известно. В json нет бинарных данных и он его берет для rpc (sic!).

По делу. Насколько помню использовать этот протокол необязательно и можно своим пользоваться, каналы сырые есть.

anonymous
()
Ответ на: комментарий от anonymous

Да конечно - можно:)

Вопрос был - не пропустил ли я чего пока читал доку по стандартной либе питона.

По поводу бинарных данных - довольно сложно представить юзекейс, где это могло бы понадобиться в продукте где приоритетная идиома «всё текст».

Ну а коли такое найдётся, никто опять же не мешает тебе использовать на raw или nl варианте что угодно, хоть protobuf хоть велосипед.

Вкуснота json протокола в этом контексте только в том, что легко дёргать коллбэки на viml со стороны сервера. Хотя удобство сравнительное, на самом деле не хватает одной thread safe функи post_event, которая клала бы вызов коллбэка в ту же очередь откуда дербанятся команды из тех же каналов :(

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

Достаточно в части сервера действительно реализовать только такую функцию, а всё остальное можно будет написать на том же питоне.

Однако - спасибо :)

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

Ну вот смотри, допустим ты читаешь с сети. Для наглядности возьмём udp. Есть характеристика сети mtu - максимум байт в пакете (обычно порядка 1500 байт). Опять же для наглядности возьмём mtu = 8.

По UDP можно слать пакет размером больше чем MTU. Получающая сторона при чтении пакета из сокета получает его размер. Не знаю что у тебя там за протокол, но кажется, что подразумевается, что 1 пакет - 1 документ.

anonymous
()

Мне кажется, что у тебя более простая задача: потоковое получение массива. Ибо мне сложно представить, как потокова получать dict и что-то с ним делать сразу же.

namezys ★★★★
()
Ответ на: комментарий от anonymous

Да про udp это чисто показать юзекейс не рассказывая почему в сокет при aio может прийти не всё сообщение или сразу два сообщения склеенных.

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от anonymous

По UDP можно слать пакет размером больше чем MTU

Если включена ip фрагментация ессно. Ибо mtu есть mtu. Или есть ещё варианты?

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от namezys

Вот когда речь идёт про датаграммы(до тех пора пока лезет) или http ответы, тут всё просто.

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

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

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

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

Я имел в виду, что делать с полученным на половину dict? Тем более порядок получения полей не гарантируется

namezys ★★★★
()
Ответ на: комментарий от namezys

Наверное имеется в виду какой нибудь потоковый парсер, который будет внутри себя хранить остаток от предыдущего буфера, и выплюнет обьект только тогда когда он придет целиком.

pftBest ★★★★
()
Ответ на: комментарий от namezys

Почитай тред целиком, мне если честно второй раз лень писать :)

В двух словах - при использовании протоколов(например tcp) отличных от тех, где на уровне транспорта есть возможность узнать о конце сообщения или о его начале(например http), имеет место быть проблема: непонятно считал ли ты с потока уже всё сообщение и можно начать парсить, или надо ещё несколько байт считать.

Вот тебе упражнение - напиши tcp-сервер [на питоне] читающий сокет с использованием

select и каждый считанный буфер за одну операцию чтения выведи на экран или в файл, обрамленную каким то разделителем (например '\n\n\n'), затем, возьми netcat и пошли большой объем текстовых данных этому серверу. Ты на практике увидишь, о чем я говорю.

Можно даже ещё проще - пусть сокет читает как то в виде read(1024). Сокет можно заменить стандартным вводом, unix сокетом, файлом, fifo, e.t.c.

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от namezys

триппером

По фрейду? Проверься:)

По делу: зависит от задачи (в частности от размеров документов), у тебя полная свобода выбора какие события обрабатывать и в какой момент. Самый частый юзекейс это всё таки получение обьекта (например, те же http запросы/ответы именно так и парсятся).

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

У меня мысль, что в общем случае оно не надо обучено.

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

namezys ★★★★
()
Ответ на: комментарий от pon4ik

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

А сам разбор уже стандартным парсером делай.

Причём если ты свой недопарсер в json.load (не json.loads) подсунешь, то документ будет парситься по мере поступления, а не дожидаться конца и только после этого парситься.

NeXTSTEP ★★
()
Ответ на: комментарий от NeXTSTEP

Ты не уточнил, есть ли на питоне быстрый «стек», чтобы написать такой парсер. Может даже простое вычитывание по одному байту может замедлить весь парсинг.

pftBest ★★★★
()
Ответ на: комментарий от NeXTSTEP

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

Согласно 404 -

123
есть полноценный json документ.

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от namezys

В общем случае как раз надо, а вот если используется http или хотя бы websocket уже не надо.

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pftBest

Стандартный парсер на самом питоне написан, так что недопарсер можно сделать не медленнее.

UPD к моему комментарию: Я наврал про json.load, стандартный парсер всё равно до конца внутри себя читает (код), так что последнее предложение не имеет смысла.

NeXTSTEP ★★
()
Ответ на: комментарий от pon4ik

Там же сбоку есть переключатель, RFC 4627 (2006 год) и RFC 7159 (2014 год). Первый требует объект или массив, а второй не требует.

pftBest ★★★★
()
Ответ на: комментарий от pon4ik

Хм, похоже там неправильный валидатор.

А как ты предлагаешь парсить 123: как три документа 1, 2 и 3 или как два 12 и 3?

NeXTSTEP ★★
()
Ответ на: комментарий от NeXTSTEP

Как один документ. Началало документа это начало number конец документа есть конец number. Т.е. вот например уже два документа:

123asd
pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

тогда у вас тот, что записано, не равно тому, что считано.

записано два раза по 1

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

namezys ★★★★
()
Ответ на: комментарий от namezys

Совершенно верно, придёт либо символ свидетельствующий о начале нового документа, либо конец ввода, либо whitespace опять же свидетельствующий о окончании документа «число». Я согласен с тем, что это не удобно, и никто так не делает, все передают либо объекты либо массивы. Но факт что поток можно однозначно разобрать никуда не исчезает от этого. То, что разбирать потоково строго согласно 404 не эффективно выходит (надо ждать конца ввода или следующего документа) это факт, кроме случаев работы например с файлом.

pon4ik ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.