Здравствуйте! Хотел бы поделиться своими проблемами. Полезно на будущее иметь в виду при выборе инструментария и при написании своего. Использую я сейчас обычно AWS, GNATCOLL.JSON и стандартную библиотеку. AWS многопоточен, и когда открывается страница с XHR подгрузками, там неиллюзорно потоки, соответствующие разным запросам, начинают в параллель идти. И, чтоб одно другому не мешало, использую встроенные средства многозадачности. AWS свои задачи создаёт, я ещё создаю и активирую по таймеру, через protected синхронизирую. Меня озаботило то, что мне приходится постоянно смотреть, а не рефлексировал ли случайно разработчик очередной библиотеки по поводу того, делать ли операции со счётчиками ссылок безопасными в многопоточной среде или делать по–аскетичному. Потому что выяснятся, что некоторые разработчики–таки рефлексируют, и эта их рефлексия доводит до того, что реализуют они именно аскетичное решение. Вот, например, GNATCOLL.JSON делали аскеты. Это значит, что если я считал файл конфигурации в формате JSON в глобальную переменную, я не могу обращаться к ней из других потоков, потому что они там неправильно надёргают счётчик ссылок, и получится чёрти что. Сначала приходится преобразовывать в структуры либо с безопасными счётчиками ссылок, как у Unbounded_String, либо с единственными ссылками, как в контейнерах, и работать потом именно с ними, даже если мне было бы так удобно сериализовать фрагмент JSON_Value внутрь сгенеренного скрипта. Этот аскетизм делает тщетными попытки защитить JSON_Value даже при помощи protected. procedure имеют исключительный доступ, они могут и читать, и писать без проблем. А вот function могут иметь одновременный доступ с аналогичными последствиями, поэтому в protected точно также приходится переносить всё в другие форматы, с которыми только и может потом работать function. Всё в процедуры не перенесёшь, практически однопоточная программа получится, функции нужны. Более строгая типизация при использовании контейнеров воспринималась как благо, поэтому с этим я ещё хоть как–то мирился. В контейнерах вроде бы как счётчика ссылок нет, потому что контейнер копируется полностью, и там уникальные ссылки, но как недавно выяснилось, аскеты нашли способ и тут нагадить. Обнаружилось, когда работал с глобальной константой–множеством строк. Возникает не сразу, но после некоторого времени после старта веб–сервера начинает возникать в каждом запросе, так и была обнаружена. Переносишь внутрь function Service — ошибка перестаёт возникать. В норме константе должно быть всё равно, глобальная она или локальная. Возникает в a-cihase.adb:1154 (GNAT GPL 2015 x86_64-linux). Там внутри какая–то другая ошибка, но из Adjust/Finalize она вылетает, превратившись в Program_Error. И что же мы там рядом видим? B : Natural renames Container'Unrestricted_Access.all.HT.Busy; ... B := B + 1; Проклятье! Эти аскеты и тут достали. Вот почему–то разработчики Delphi, гораздо более неудобного для многопоточной разработки языка, не рефлексировали и вкатили потокобезопасные счётчики везде, куда могли. Даже на восходящие замыкания не пожалели. InterlockedIncrement, и голова не болит. Ни у того, кто пишет, ни у того, кто потом пользуется. А в Аде, получается, все стандартные контейнеры — шлак, и под нагрузкой это всплывёт, когда уже будет поздно всё менять. А теперь приятная новость: я посмотрел исходники стандартной библиотеки в GNAT GPL 2016 и GNATCOLL.JSON оттуда же и был приятно удивлён, что там как раз это и починили. Об этом нигде не написали в новостях, но это так. Контейнеры в GNAT GPL более ранних версий не пригодны для разработки многопоточных программ, но теперь ещё одна детская болезнь позади. С уважением, Левашев Иван, Барнаул -- If you want to get to the top, you have to start at the bottom
07.10.2016 2:08, Vadim Godunko vgodunko@... [ada_ru] пишет: > Вот от себя отмечу, что атомарные счётчики ссылок - очень дорогая идея в > современном мире многопроцессорных/ядерных/нитевых технологий. Применять > её имеет смысл только когда она необходима и решает необходимые задачи. > И как только она применена - усё, все другие применения кода не имеют > права на жизнь. Здравствуйте! Мне пришла в голову такая идея оптимизации: При создании и уничтожении (если обычным чтением посмотрели и увидели только одну ссылку) барьер не использовать, так как владение монопольное. Если оно вдруг перестаёт быть таким, то в другом ядре исполнение не продолжится, пока из кеша этого не вылетит старое значение. Дополнительно к счётчику ссылок добавить специальное поле для номера потока, изначально заполненное. Адский компилятор тяжело будет заставить так работать, но в идеале нужно избегать множественных ссылок (>=2). Для локальных переменных нужно будет реализовать limited read-only ссылку, которая убедится, что идентификатор потока заполнен и совпадает, и тогда не будет ничего делать, либо увеличит счётчик ссылок. Если не совпадает, то надо поставить барьер, стереть идентификатор потока навсегда из этого объекта и увеличить счётчик. На обратном пути каждая такая ссылка отменит своё действие, кроме стирания идентификатора потока. Чтобы не возникало путаницы, ссылки как раз и должны быть limited только для чтения, то есть, чётко на стеке и во время исполнения одного потока отгораживать внутреннюю область от внешней, иначе как понять, сколько обращений к счётчику ссылок было пропущено. Возможно, при помощи дополнительных указателей в каждой ссылке (например, указатель, при создании указывающий на ссылку, а при копировании позволяющий что-то сделать с прежней версией ссылки по этому указателю; а также идентификатор потока, в котором была создана ссылка) примерно такое поведение получится сделать для копируемых (private) изменяемых ссылок. Может быть, копируемые изменяемые ссылки можно сделать, если сверять номер потока и в зависимости от результата сравнения инкрементировать/декрементировать в любом случае, но ставить барьер только при стёртом номере потока. Сложно оценить корректность и производительность в каждом случае. С уважением, Левашев Иван, Барнаул -- If you want to get to the top, you have to start at the bottom
On 2016-10-06 22:30, Иван Левашев octagram@... [ada_ru] wrote: > > > Вот, например, GNATCOLL.JSON делали аскеты. Это значит, что если я > считал файл конфигурации в формате JSON в глобальную переменную, я не > могу обращаться к ней из других потоков, потому что они там неправильно > надёргают счётчик ссылок, > От куда такая информация ? И какую версию GNATCOLL имеете в виду ?
On 2016-10-06 22:30, Иван Левашев octagram@... [ada_ru] wrote: > > > Возникает в a-cihase.adb:1154 (GNAT GPL 2015 x86_64-linux). > Перейдите для начала на GNAT GPL 2016. Проблема с многозадачным чтением контейнеров уже решена наверное с год назад в GNAT pro попала ли эта поправка в GNAT GPL 2016 пока точно сказать не могу.
On 2016-10-06 23:33, Dmitriy Anisimkov wrote: > On 2016-10-06 22:30, Иван Левашев octagram@... [ada_ru] wrote: >> >> >> Возникает в a-cihase.adb:1154 (GNAT GPL 2015 x86_64-linux). >> > Перейдите для начала на GNAT GPL 2016. > Проблема с многозадачным чтением контейнеров уже решена > наверное с год назад в GNAT pro попала ли эта поправка в GNAT GPL 2016 > пока точно сказать не могу. Почитал рантайм GNAT GPL 2016. Конкуррентное чтение контейнеров должно быть без проблем. В GNAT GPL 2015 была такая проблема, когда контейнеры читались одновременно несколькими потоками, сбивался внутренний счетчик ссылок. Кроме того, в 2016 появилась прагма которая может вообще выключить внутренние ссылки в контейнерах, https://gcc.gnu.org/onlinedocs//gnat_rm/Pragma-Suppress.html смотреть Container_Checks и Tampering_Check тогда даже на тех платформах где не поддеживаются атомарные счетчики с конкуррентным чтением контейнеров проблем не будет.
On 10/06/2016 06:30 PM, Иван Левашев octagram@... [ada_ru] wrote: > > Хотел бы поделиться своими проблемами. Полезно на будущее иметь в виду > при выборе инструментария и при написании своего. > Вот от себя отмечу, что атомарные счётчики ссылок - очень дорогая идея в современном мире многопроцессорных/ядерных/нитевых технологий. Применять её имеет смысл только когда она необходима и решает необходимые задачи. И как только она применена - усё, все другие применения кода не имеют права на жизнь. Вот сделали что бы контейнеры были доступны по чтению из нескольких нитей. Правильно же сделали, да? А в другом месте, в однонитевой программе это привело к тому, что более 30% времени CPU буксовал на атомарных операциях. Так что аккруатнее с желаниями, они могут сбыться ;)
07.10.2016 2:08, Vadim Godunko vgodunko@... [ada_ru] пишет: > On 10/06/2016 06:30 PM, Иван Левашев octagram@... [ada_ru] wrote: >> >> Хотел бы поделиться своими проблемами. Полезно на будущее иметь в виду >> при выборе инструментария и при написании своего. >> > Вот от себя отмечу, что атомарные счётчики ссылок - очень дорогая идея в > современном мире многопроцессорных/ядерных/нитевых технологий. Применять > её имеет смысл только когда она необходима и решает необходимые задачи. > И как только она применена - усё, все другие применения кода не имеют > права на жизнь. А откуда у неё цена–то такая? По MESI состояние между M и E меняется. Если состояние было не S, всё как в одном потоке. Ну переупорядочивание ещё не работает со счётчиками. Может быть, просто у LOCK ADD какие–то побочные эффекты, которые можно утрясти со временем в других архитектурах или других опкодах? > Вот сделали что бы контейнеры были доступны по чтению из нескольких > нитей. Правильно же сделали, да? А в другом месте, в однонитевой > программе это привело к тому, что более 30% времени CPU буксовал на > атомарных операциях. Так что аккруатнее с желаниями, они могут сбыться ;) Я использую стандартную библиотеку, зная о том, что она, особенно с моими флагами компиляции, не самая быстрая, но мне нужно отсутствие сюрпризов или хотя бы информативность в случае таковых, и стандартные контейнеры мне это давали. Это общий дух стандартной библиотеки, и исправление в 2016 замечательно соответствует ему. Eсть 100500 других библиотек контейнеров, написанных аскетами, адаистам на такое «везёт», и там много всякого другого тормозящего подрезано, так что их, наверное, и стоило бы взять, если так нужно. С уважением, Левашев Иван, Барнаул -- If you want to get to the top, you have to start at the bottom
On 2016-10-07 01:08, Vadim Godunko vgodunko@... [ada_ru] wrote: > > > On 10/06/2016 06:30 PM, Иван Левашев octagram@... [ada_ru] > wrote: > > > > Хотел бы поделиться своими проблемами. Полезно на будущее иметь в виду > > при выборе инструментария и при написании своего. > > > Вот от себя отмечу, что атомарные счётчики ссылок - очень дорогая идея в > современном мире многопроцессорных/ядерных/нитевых технологий. Применять > её имеет смысл только когда она необходима и решает необходимые задачи. > И как только она применена - усё, все другие применения кода не имеют > права на жизнь. > > Вот сделали что бы контейнеры были доступны по чтению из нескольких > нитей. Правильно же сделали, да? А в другом месте, в однонитевой > программе это привело к тому, что более 30% времени CPU буксовал на > атомарных операциях. Так что аккруатнее с желаниями, они могут сбыться ;) > Хочу напомнить, что в текущем сосотоянии GNAT стандартных контейнерах есть возможность убрать счетчики совсем и сохранить конкурентное чтение. pragma Suppress (Containers_Check);
Чтобы оставить новое сообщение необходимо Зарегистрироваться и Войти