|
|
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
Доброго дня всем! INTRO: Есть несколько экземпляров работающей проги на одной машине. Каждая из них добывает JSON массив некоторых данных, парсит, обрабатывает его, и обработанный результат записывает в переменную TRecord = record... Этими уже обработанными данными нужно поделиться с другими экземплярами. В итоге каждый экземпляр должен иметь общий список всех данных всех экземпляров. Для решения этой задачи я использую Memory Mapped Files. Т.е. у каждого экземпляра есть свой такой общедоступный Memory Mapped File. Вопрос: как в таком файле хранить значение типизированной переменной? В типе есть строки неопределенной длины и есть динамические массивы, длина которых заранее не известна. Что я уже попробовал? 1. Я использовал в InMemory SQL. Создал таблицы для хранения этих данных, а в Memory Mapped Files хранил SQL дампы каждого экземпляра. В итоге каждый экземпляр мог пробежаться по всем MMF, собрать общий дамп и заполнить из него базу. В итоге у каждого экземпляра была своя копия общей базы, и эти копии были у всех одинаковы. Но эту процедуру нужно делать раз в секунду. Когда начал тестировать - увидел что ежесекундное создание новой копии базы из SQL дампа, да еще и на нескольких экземплярах программы - это все значительно увеличивает нагрузку на проц. Решил отказаться. 2. Затем я выкинул InMemory SQL, и в MMF стал хранить просто JSON массивы в виде строк. В итоге опять же каждый экземпляр мог пробежаться по всем MMF, обработать JSON массив и создать свою копию общего списка данных. И опять же, когда начал тестировать - увидел что вот это вот "обработать" грузит проц. Фактически каждый экземпляр делает одну и ту же работу, в то время когда каждый может обработать свою порцию данных и поделиться ей с другими. Собственно отсюда и вопрос: есть переменная array of TMyType . В TMyType есть поля - динамические массивы. Нужно как то записать это все в Memory Mapped File чтоб другой экземпляр мог считать уже обработанные данные в свой array of TMyType. Может как то можно этот array сериализовать в поток? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 11:10 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinВ итоге у каждого экземпляра была своя копия общей базы зачем? пуст ьи дальше пользуются этой общей базой. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 11:36 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
у тебя фактически получается что-то типа распределённого кэша. "обработанными данными нужно поделиться с другими экземплярами" соответственно тебе и копать в сторону cache coherency алгоритмов. чтобы каждый раз, когда допустим переменную X хотят модиффицироват ьдве программы, одна из нихъ это начинала делать, а другая ждала своей очереди, а потом по реезультату работы второй - и первая её перечитывала, знала что после неё уже снова изменили. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 11:39 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
Ariochу тебя фактически получается что-то типа распределённого кэша. "обработанными данными нужно поделиться с другими экземплярами" соответственно тебе и копать в сторону cache coherency алгоритмов. чтобы каждый раз, когда допустим переменную X хотят модиффицироват ьдве программы, одна из нихъ это начинала делать, а другая ждала своей очереди, а потом по реезультату работы второй - и первая её перечитывала, знала что после неё уже снова изменили. Не совсем. Переменные менять не нужно. Каждый экземпляр имеет у себя свой обработанный массив данных. Этот массив уже никто менять не будет - ни сама программа, ни другие экземпляры. Поэтому вот эта функциональность Ariochчтобы каждый раз, когда допустим переменную X хотят модиффицироват ьдве программы, одна из нихъ это начинала делать, а другая ждала своей очереди, а потом по реезультату работы второй - и первая её перечитывала, знала что после неё уже снова изменили. ..не требуется. На запрос "cache coherency delphi" гугл ничего дельного не выдает. Когда требуется общая память - в большинстве случаев используют Memory Mapped File. Мой вопрос только в том, как в нем хранить массивы некоторых структурированных данных. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 11:55 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinНа запрос "cache coherency delphi" гугл а при чём тут delphi ? это общие алгоритмы, пиши их на чём хочешь. https://en.wikipedia.org/wiki/Cache_coherence > Этот массив уже никто менять не будет Тогда строй очереди. Что-то типа D-BUS Очередь заданий на обсчёт (не просчитанных ещё объектов) и отдельно Очередь обсчитанных объектов Учитывай, что твои экземпляры программ могут зависнуть/отвалиться Очереди обычно реализуются через "кольцевой буфер". Но ожно и через списки, если важно удалять/вставлять в середину очереди. Т.е. на вход первой очереди поступает нерассчитанный элемент. ХЗ откуда - не важно. Главное факт "это надо посчитать" Потом с выхода первой очереди берется необсчитанная задача, но с очереди не удаляется - помечается "я, программа номер такая-то (Process-ID или Thread-ID или ещё что) взяла этот элемент в работу в такое-то время (например GetTickCount), другие программы такую задачу не берут себе. Когда она его заканчивает - она его удаляет с первой очереди и вставляет во вторую. Если за вменяемое время задача не просчитана - считаем, что программа номе N умерла, отключаем её от обоих очередей, задачу снова помечаем как необработанную и свободную для всех. Поскольку она по прежнему торчит на самом выходе - её тут же кто-то другой возьмёт в работу. На очереди №2 все вставленные элементы (результаты расчетов) помечаются количеством подключённых к очереди "читателей" (а можно и полный список ID читателей, но это памяти больше возьмёт) на момент вставки элемента. Каждый читатель уменьшает счётчик. Когда счетчик доходит до нуля - элемент снимается с очереди "(все и так его прочитали)". Фактически, это обычный счётчик ссылок - ARC, аналогично string и interface типам. Опять же, надо отрабатывать ситуации "посреди работы в очередь №2 влез ещё один новый читатель" или "программа №N считается безвременно погибшей и отключается от обоих очередей". Они легко и просто не отработаются, тут придется потратить время на опрос ВСЕХ программ, но и возникать они будут крайне редко. Само собой, что все изменения признаков должны проводиться атомарными функциями ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 12:09 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinМожет как то можно этот array сериализовать в поток?можно, TTypeMarshaller достаточно, смотри как пример TJSONMarshal в REST.JsonReflect ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 12:54 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinЭтими уже обработанными данными нужно поделиться с другими экземплярами. Нужен обычный брокер сообщений с моделью N producer M consumer На выбор: Kafka, RabbitMQ, Redis Ну или свой лисапет ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 13:27 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
pub-sub нужен что для Windows есть вместо D-Bus ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 13:41 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinМожет как то можно этот array сериализовать в поток?Перед каждым полем переменной длины пиши в поток эту длину Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 13:56 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
Коллеги, гигантское спасибо за ответы и помощь! Буду пробовать все варианты. X-CiteНужен обычный брокер сообщений с моделью N producer M consumer На выбор: Kafka, RabbitMQ, Redis Ну или свой лисапет У меня сейчас фраза "поделиться данными" реализована с помощью MySQL. Т.е. каждый шлет свои данные запросом и может в любой момент получить общие данные. Но цель переделок - избавиться от централизации в виде MySQL сервера и вообще от каких либо сторонних программ. Я искренне верю что можно не палить из пушки по воробьям и программы, работающие на одной машине могут договариваться сами, а не через какое либо приложение. Остальные варианты буду пробовать. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 18:59 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinКоллеги, гигантское спасибо за ответы и помощь! Буду пробовать все варианты. X-CiteНужен обычный брокер сообщений с моделью N producer M consumer На выбор: Kafka, RabbitMQ, Redis Ну или свой лисапет У меня сейчас фраза "поделиться данными" реализована с помощью MySQL. Т.е. каждый шлет свои данные запросом и может в любой момент получить общие данные. Но цель переделок - избавиться от централизации в виде MySQL сервера и вообще от каких либо сторонних программ. Я искренне верю что можно не палить из пушки по воробьям и программы, работающие на одной машине могут договариваться сами, а не через какое либо приложение. Остальные варианты буду пробовать. https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-broadcastsystemmessage https://docs.microsoft.com/en-us/windows/desktop/winmsg/about-messages-and-message-queues#broadcasting-messages ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 20:03 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinможно не палить из пушки по воробьям Можно, но иногда "не палить из пушки" означает "изобретать велосипеды", в частности долбиться о пробелмы и ошибки, об которые "в пушках" уже обдолбились и давно поправили MySQL возможно тяжеловатый сервер. Тот же Firebird легче. SQLite ещё легче, если в нём возможно один файл читать из разных процессов. А главное, тебе надо решить что ты делаешь, push или pull ? dundinкаждый .... может в любой момент получить общие данные Это - Pull. Никто никому никаких данных не приносит. Наоборот, кому поднадобилось - тот и ищёт, когда понадобилось. dundinЭтими уже обработанными данными нужно поделиться с другими экземплярами. А это - Push. Если я что-то приготовил, я обхожу каждого и ему это всовываю. Даже если тебе это нафиг не надо и никогда не понадобится - мне про это неизвестно, я всё равно тебя найду и засуну тебе это в зубу и заставлю проглотить - просто на всякий случай. Иногда лучше первый подход, иногда - второй. У второго подхода есть варианты, когда в зубы всовывают не всё подряд, а тоьлко подходящее под некоторые условия (аналогично select с where и без). Это называют pubsub - publish/subscribe Это называют message bus или data bus (например D-bus на Линуксе) Это называют "брокер сообщений" - Message Queue. Например, в самой Windows часть Distributed-COM https://en.wikipedia.org/wiki/Microsoft_Message_Queuing https://www.osp.ru/winitpro/2002/08/175133/ В частности cache coherence обычно объединяет оба подхода но для разных данных. Сообщения "я тут что-то поменял, если у тебя есть копия - выкинь её немедленно" идёт как push. А вот реальный пакет с данными, если понадобится, как pull. В общем, палитра у тебя примерно такая, краску смешивай исходя из твоей реальной задачи и реальных в ней потоков данных. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 20:04 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
+ WM_COPYDATA каждое броадкастом уведомляет всех: Вот он я, запишите мой хендл. либо уведомляет я закрываюсь не шлите мне. А через WM_COPYDATA уже передаете данные ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 20:05 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinНо цель переделок - избавиться от централизации в виде MySQL сервера и вообще от каких либо сторонних программ. Супер! Выкинь нафиг Delphi RTl а также Delphi VCL и Delphi FMX - они ведь тоже "сторонние программы". Напиши всё сам. Это возможно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 20:07 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
X-Citeлибо уведомляет я закрываюсь не шлите мне ...либо жёстко крэшится посреди транзакции и никого ни о чём не уведомляет. А респондент остаётся висеть в середине обмена, ожидая сообщения, которое уже никогда не придёт... Лисапеты - они такие. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 20:08 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
AriochX-Citeлибо уведомляет я закрываюсь не шлите мне ...либо жёстко крэшится посреди транзакции и никого ни о чём не уведомляет. А респондент остаётся висеть в середине обмена, ожидая сообщения, которое уже никогда не придёт... Лисапеты - они такие. Если consumer покрешился, то producer будет слать в невалидный хендл.. Из условия задачи сказано надо делится данными.. ну поделится в пустоту ничего страшного... суть обмена как я понял. отдал и забыл ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 20:12 |
|
||
|
Сохранение типизированной переменной в Memory Mapped File
|
|||
|---|---|---|---|
|
#18+
dundinизбавиться от централизации в виде MySQL сервера Кстати, как ты отлаживать-то будешь ? Вот допустим у тебя, или у клиетна, "что-то пошло не так". Допустим, ты даже смог это воспроизвести. С SQL-сервером ты можешь заглянуть в процессе отладки в БД и посмотреть, что там реально где происходит в любйо момент работы программы. У разных MSMQ и RabbitMQ тоже наверное свои инструменты есть, но они менее известные и менее тебе привычнее. Для собственного велосипеда ты такие средства будешь придумывать и писать сам. Централизацию не на пустом месте придумали. Децентрализация возможна, но она не бесплатна. Ту же очередь "N producer M consumer" можно внутри Firebird БД держать. Опять же, как часто ты что делаешь. Если у тебя 100 сообщений в секунду, каждое по 20 КБ - то SQL-сервер прекрасно подойдёт. Закеширует "горячую" часть БД в память и будет молотить. Если у тебя 100 000 сообщений в секунду каждое по 20 байт - то сервер ляжет, накладных расходов будет в разы больше, чем данных. Впрочем, тут и WM_COPYDATA ляжет наверное. Если у тебя одно сообщение в час, но оно сразу по гигабайту - WM_COPYDATA сразу пролетает, SQL будет скрипеть и плакать, тут лучше файлами обмениваться. В общем, какие у тебя данные - от этого и танцуй ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.03.2019, 20:16 |
|
||
|
|

start [/forum/topic.php?fid=58&msg=39785822&tid=2039695]: |
0ms |
get settings: |
7ms |
get forum list: |
21ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
411ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
78ms |
get tp. blocked users: |
1ms |
| others: | 214ms |
| total: | 754ms |

| 0 / 0 |
