На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
Страницы: (16) « Первая ... 6 7 [8] 9 10 ...  15 16 все  ( Перейти к последнему сообщению )  
> Thread-safe shared_ptr , Реализация потоко-безопасного SharedPtr
    Цитата Flex Ferrum @
    А расскажите, в каких областях требуется управлять тысячам (или сотнями тысяч) подписчиков в рамках паттерна publisher-subscriber? Мне вот даже интересно стало.


    У меня сейчас ~4000 коннектов по сокетам на сервере, это постоянных, на подписке. Каждый из них в свою очередь подписываются на какие-то данные, изменения данных, в рамках того самого паттерна. Примерно раз в секунду происходит коннект-дисконнект, какие-то коннекты отваливаются, но в основном сидят подолгу. Подписаны они на события из базы данных и котировки. Обновления идут очень часто. По событиям из базы данных вызываются процедуры, вообще асинхронно, но определённая синхронизация есть, иначе никаких потоков не хватит. Ещё выполняются скрипты, JavaScript - google V8, тоже асинхронно.

    Область - веб-сервер начитывает данные с моего сервера. Онлайн-брокер.

    Цитата Flex Ferrum @
    Кстати, в твоём примере выше ты зачем-то дважды по списку пробегаешься при нотификации.


    Кстати, в моём примере, благодаря отказу от чудовищной Unsubscribe, появилась возможность избежать этой двойной пробежки (или копирования, что одно и тоже):
    - под блокировкой сделать move;
    - пробежаться по списку, вызвать функции или удалить отписавшихся;
    - под блокировкой сделать splice.
    Тогда можно будет вообще забыть 10 у тебя клиентов или 10000.

    Цитата Flex Ferrum @
    И я, образно говоря, не вижу смысла покупать бентли только чтобы на дачу ездить. У меня в проекте другие узкие места, которые требуют агрессивной оптимизации.


    Это не вопрос "агрессивной оптимизации", это скорее вопрос гигиены.
    Сообщение отредактировано: Олег М -
      А каждый подписывается на свои виды котировок и все получают всё?
        Каждый на свой перечень, подписка идёт от клиента, из браузера
          Я бы предложил тебе в сторону того, как реализован гугловый gRpc. Возможно, подсмотришь чего интересное. А пока такой вопрос: ты уверен, что правильный паттерн выбрал для реализации? И самое узкое место - в работе с shared-указателями?
            Цитата Flex Ferrum @
            А пока такой вопрос: ты уверен, что правильный паттерн выбрал для реализации? И самое узкое место - в работе с shared-указателями?


            Ну, реализация паттерна, как ты заметил, примерно такая же, как у тебя. Кроме той блокировки, отличий, собственно, не найдёшь. У тебя хорошая, очень грамотная реализация (кроме Unsubscribe!!!).

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

            Добавлено
            Цитата Flex Ferrum @

            Wizard

            Профиль · PM
            Поощрения: 25 Dgm
            Рейтинг (т): [ 495 ]
            Я бы предложил тебе в сторону того, как реализован гугловый gRpc. Возможно, подсмотришь чего интересное.


            Дай ссылку. Хотя я не любитель гугловских реализаций. Интерфейс V8 написан школьником задней левой ногой. Я себе всю башку сломал, пока худо-бедно разобрался, сто раз пожалел, что связался.
            Сообщение отредактировано: Олег М -
              Цитата Олег М @
              Цитата Flex Ferrum @
              А пока такой вопрос: ты уверен, что правильный паттерн выбрал для реализации? И самое узкое место - в работе с shared-указателями?


              Ну, паттерн, как ты заметил, примерно такой же, как у тебя. Кроме той блокировки, отличий.

              Так вот я и не уверен, что pub-sub тут подходит. Тут наклевывается реактор с producer-consumer или авторами (тут недалеко есть темка с SObjectizer). И асинхронной рассылкой данных.
              Кстати, смысла так упарываться со сморт-поинтерами, атомиками и прочим особого не вижу. Освобождение ресурсов, связанных с конкретным коннектом, занимает дохрена времени само по себе. Как, впрочем, и отправка данных в сеть.
                Я очень слабо разбираюсь в паттернах, названия мне ничего не говорят

                Собственно, сервер подписок работает примерно по той же схеме - копия списка под блокировкой, обработка и т.д. Только обработка заключается в том, что
                - для каждого подписчика запускается поток из пула
                - он получает список изменённых данных, либо сообщения
                - вызывает функцию подписчика

                С указателями не упарываешься - написал один раз и забыл навсегда

                Добавлено
                Цитата Flex Ferrum @
                Тут наклевывается реактор с producer-consumer или авторами (тут недалеко есть темка с SObjectizer).

                Где?
                  Тем не менее. Я так и не уверен, что мой код работает. Кто–нибудь может мне объяснить помогло добавление volatile к std::atomic или нет? Если помогло, то каким образом?
                    Цитата Олег М @
                    Это не вопрос "агрессивной оптимизации", это скорее вопрос гигиены.

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

                    Ссылки:
                    GRPC
                    SObjectizer 5.3.0

                    Цитата Олег М @
                    Я очень слабо разбираюсь в паттернах, названия мне ничего не говорят
                    Собственно, сервер подписок работает примерно по той же схеме - копия списка под блокировкой, обработка и т.д. Только обработка заключается в том, что
                    - для каждого подписчика запускается поток из пула
                    - он получает список изменённых данных, либо сообщения
                    - вызывает функцию подписчика

                    Давай разберёмся. У тебя некий сервер, работающий с браузерами по протоколу HTTP/HTTPS 1.1 (минимум). Браузеры коннектятся к серверу, формируют запрос на котировки, после чего сервер по установленному соединению шлёт запрошенные котировки, пока клиент не отвалится. Таких клиентов - штук 4000 минимум. Чтобы отправить котировки сервер должен обратиться к БД, выбрать нужные, определить клиентов, которым нужны те или иные тикеты, после чего сформировать ответы и послать. В виде, видимо, JSON.
                    Вопрос номер раз: ты уверен, что игрища с "коллекциями подписчиков" - это наиболее горячее место, требующее оптимизации? А что сказал какой-нибудь Intel VTune? Он вообще что-нибудь сказал?
                    Вопрос номер два: почему, собственно, тебя беспокоит скорость подписки/отписки клиентов в "менеджере подписок", если это заведомо тяжёлые операции? В первом случае - получить запрос (в виде текста, замечу), распарсить, что-нибудь куда-нибудь положить, модифицировать список получаемых из БД тикетов. Отписка - освободить все ресурсы, память, модифицировать запрос к БД и т. п.
                    Вопрос номер три: верно ли утверждение, что данные о тикетах отправляются сразу в сокет и в текстовом виде? Если да, то тебя на фоне этой операции действительно беспокоит, насколько долго будут лочится списки подписчиков? Уточню: надо сформировать HTTP-ответ (в текстовом виде), зашифровать его (если работа по SSL), отправить в сокет (пусть и асинхронно), отхендлить ошибки типа отвалившихся клиентов, внезапно упавшей сети и прочие прелести.
                    Кроме того, 4000 клиентов - это не то, чтобы много, на самом деле, для веб-сервиса.
                    Вопрос номе четыре: (главный, возвращаясь, так сказать, к началу комментария) а какова, собственно, цель оптимизации? Написать for fun потокобезопасный SmartPointer - это, конечно, весело. Но при работе с продакшен-кодом любая активность должна иметь некую цель, завязанную на бизнес-задачи. В данном случае какую проблему ты решаешь, пытаясь оптимизировать одни этот конкретный участок? И тот ли участок ты оптимизируешь?
                      Цитата Flex Ferrum @
                      Давай разберёмся. У тебя некий сервер, работающий с браузерами по протоколу HTTP/HTTPS 1.1 (минимум). Браузеры коннектятся к серверу, формируют запрос на котировки, после чего сервер по установленному соединению шлёт запрошенные котировки, пока клиент не отвалится. Таких клиентов - штук 4000 минимум. Чтобы отправить котировки сервер должен обратиться к БД, выбрать нужные, определить клиентов, которым нужны те или иные тикеты, после чего сформировать ответы и послать. В виде, видимо, JSON.


                      Сервер, вернее один из серверов, - по сути просто кэширует данные, которые хранятся в базе данных и отдаёт их либо по rpc-запросу, либо по подписке клиенту. Данные в кэше обновляются асинхронно, по сигналам из базы. Ещё, по запросам выполняются ява-скрипты, которые получают данные из памяти сервера, делают какие-то вычисления и возвращают результат.
                      Он не работает с браузеры, запросы идут от веб-серверов, по сокетам, TCP.


                      Цитата Flex Ferrum @
                      Вопрос номер раз: ты уверен, что игрища с "коллекциями подписчиков" - это наиболее горячее место, требующее оптимизации? А что сказал какой-нибудь Intel VTune? Он вообще что-нибудь сказал?
                      Вопрос номер два: почему, собственно, тебя беспокоит скорость подписки/отписки клиентов в "менеджере подписок", если это заведомо тяжёлые операции? В первом случае - получить запрос (в виде текста, замечу), распарсить, что-нибудь куда-нибудь положить, модифицировать список получаемых из БД тикетов. Отписка - освободить все ресурсы, память, модифицировать запрос к БД и т. п.


                      Ну, во-первых я там ничего не оптимизирую, там и так всё нормально работает. Во-вторых, меня не беспокоит скорость подписки/отписки - куда ещё быстрее?. Это должно беспокоить тебя.

                      Цитата Flex Ferrum @
                      Вопрос номер три: верно ли утверждение, что данные о тикетах отправляются сразу в сокет и в текстовом виде? Если да, то тебя на фоне этой операции действительно беспокоит, насколько долго будут лочится списки подписчиков?


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


                      Цитата Flex Ferrum @
                      Кроме того, 4000 клиентов - это не то, чтобы много, на самом деле, для веб-сервиса.

                      У меня не веб-сервис. 4000 (тут, признаюсь, немного приврал, такой цифры я не видел. В среднем - 3500) это коннекты по веб-сокетам, постоянные. RPC-коннекты я не считаю, но в среднем где-то один в секунду.


                      Цитата Flex Ferrum @
                      Вопрос номе четыре: (главный, возвращаясь, так сказать, к началу комментария) а какова, собственно, цель оптимизации? Написать for fun потокобезопасный SmartPointer - это, конечно, весело. Но при работе с продакшен-кодом любая активность должна иметь некую цель, завязанную на бизнес-задачи. В данном случае какую проблему ты решаешь, пытаясь оптимизировать одни этот конкретный участок? И тот ли участок ты оптимизируешь?


                      У меня сервер работает на машине с 4 процессорами и 16Гб памяти. Хранит данные о 50тыс аккаунтов и 15тыс инструментов, постоянно обновляет их и рассылает подписчикам. Как ты думаешь у меня там есть возможность делать что-то не оптимально (хотя, конечно, косячу регулярно)?

                      Потокобезопасный указатель означает, что мне не надо использовать дополнительных средств, ресурсов и блокировок при работе с этим классом. Это не от хорошей жизни, поверь.
                        Цитата Олег М @
                        Тем не менее. Я так и не уверен, что мой код работает. Кто–нибудь может мне объяснить помогло добавление volatile к std::atomic или нет?

                        Поиск мелких багов - довольно утомительная (хотя и интересная) работа.
                        И не всегда простая.
                        Кто-же выполнит её за тебя ?
                        ---
                        А что такое "volatile" ?
                        Это запрет регистровой оптимизации для переменных.
                        Т.е. если объявлена некая переменная, компилятор из соображений
                        оптимизации может разместить переменную в регистр.
                        Часто это бывает с счётчиками циклов.
                        ---
                        Ничего подробно не знаю про std::atomic.
                        Но это шаблонный класс.
                        Вряд ли его экземпляр разместят в регистре.
                        Задача этого класса - гарантировать атомарность операций.
                        Для его пользователя не важно, как он устроен внутри.
                        Сообщение отредактировано: ЫукпШ -
                          Цитата ЫукпШ @
                          Поиск мелких багов - довольно утомительная (хотя и интересная) работа.
                          И не всегда простая.
                          Кто-же выполнит её за тебя ?


                          Я не прошу выискивать мелкие баги, прошу лишь посмотреть на код свежим взглядом. Одна ошибка обнаружилась, вроде ты же на неё и указал, думаю, не особо копаясь в коде.

                          Насчёт atomic - да, я тоже раньше думал, что ему не требуется volatile. Видимо, это не так. У него и методы идут парами - один с volatile, другой без.
                            [quote=Flex Ferrum,1485242843,3703624]3. (важно!) обеспечивается синхронизация между отпиской клиента и его нотификацией. Если этой синхронизации не будет, то клиент (каждый!) должен будет работать из расчёта на то, что отписка ничего не гарантирует. И после отписки ему всё равно могут придти вызовы. Клиентов обычно очень расстраивает этот факт.[/quo

                            Не рассказал, как я решаю эту проблему (вернее, она решалась довольно коряво, стыдно было рассказывать).
                            У меня тоже есть дескриптор подписчика, причём в единственном экземпляре, noncopyable. Он хранит у себя shared_ptr на подписчика(теперь CSharedPtr), дублирует его интерфейс (тут, наверное, можно было бы и унаследоваться). Но, методе reset() ждёт, чтобы все экземпляры на его указатель были уничтожены
                            ExpandedWrap disabled
                              void reset() noexcept
                              {
                                  if (!m_sp)
                                      return;
                               
                                  TS::CWeakPtr<T> sp = m_sp;
                                  m_sp.reset();
                                  while (!sp.expired())
                                      std::this_thread::yield();
                              }
                              Цитата Олег М @
                              Одна ошибка обнаружилась, вроде ты же на неё и указал, думаю, не особо копаясь в коде.

                              Да я не полагал, что это - ошибка. Это недостаток.
                              ---
                              Попробуем сначала.
                              1. Будем писать шаблонный класс SP - группа объектов указывает на какой-то объект в памяти.
                              SP должен уметь создать группу, уничтожить группу и объект, присоединиться к группе, отсоединиться
                              от группы. Обеспечить доступ к объекту. Желательно возможность модификации объекта как-нибудь по-проще.
                              2. Имеется счётчик ссылок.
                              3. Предполагаем волюнтаристским способом, что создание или уничтожение группы - потокобезопасно (ПБ).
                              Поскольку оба действия предполагают наличие только одного объекта SP.

                              Достаточно таких возможностей ?

                              4. Значит, надо обеспечить ПБ только на изменение (инкремент/декремент) или установку значения счётчика ссылок.
                              5. Варианты создания объекта группы:
                              a) с критической секцией.
                              б) с использованием "Interlocked" функций WINAPI
                              MSDN
                              Выбирай, что больше нравится.
                              Никто никого нигде специально не ждёт. Модифицируем переменную WINAPI функцией.

                              Вроде всё.
                              ---
                              А что за клиент - если не секрет ? Игрушка ?
                                Как раз это реальная ошибка, на поиски которой я б в последствии потратил бы кучу времени. Не скажу, что она явно проявилась, но в любом случае – тебе огромнейшее спасибо.
                                На остальные вопросы отвечу чуть позже.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (16) « Первая ... 6 7 [8] 9 10 ...  15 16 все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0560 ]   [ 16 queries used ]   [ Generated: 18.07.25, 16:05 GMT ]