Ada_Ru форум

Обсуждение языка Ада

Что одним аскетизм, то другим геморрой (про счётчики ссылок)

Оставить новое сообщение

Сообщения

Иван Леваше
Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-11-06 16:30:23
Здравствуйте!

Хотел бы поделиться своими проблемами. Полезно на будущее иметь в виду
при выборе инструментария и при написании своего.

Использую я сейчас обычно 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
Иван Леваше
Re: Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-10-22 05:10:56
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
Dmitriy Anisimkov
Re: [ada_ru] Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-11-06 17:27:08
On 2016-10-06 22:30, Иван Левашев octagram@... [ada_ru] wrote:
>  
>
> Вот, например, GNATCOLL.JSON делали аскеты. Это значит, что если я
> считал файл конфигурации в формате JSON в глобальную переменную, я не
> могу обращаться к ней из других потоков, потому что они там неправильно
> надёргают счётчик ссылок,
>
От куда такая информация ?
И какую версию GNATCOLL имеете в виду ?
Dmitriy Anisimkov
Re: [ada_ru] Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-11-06 17:33:48
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
пока точно сказать не могу.
Dmitriy Anisimkov
Re: [ada_ru] Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-11-06 17:47:15
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
тогда даже на тех платформах где не поддеживаются атомарные счетчики с
конкуррентным чтением
контейнеров проблем не будет.
Vadim Godunko
Re: [ada_ru] Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-11-06 19:08:30
On 10/06/2016 06:30 PM, Иван Левашев octagram@... [ada_ru] wrote:
>
> Хотел бы поделиться своими проблемами. Полезно на будущее иметь в виду
> при выборе инструментария и при написании своего.
>
Вот от себя отмечу, что атомарные счётчики ссылок - очень дорогая идея в 
современном мире многопроцессорных/ядерных/нитевых технологий. Применять 
её имеет смысл только когда она необходима и решает необходимые задачи. 
И как только она применена - усё, все другие применения кода не имеют 
права на жизнь.

Вот сделали что бы контейнеры были доступны по чтению из нескольких 
нитей. Правильно же сделали, да? А в другом месте, в однонитевой 
программе это привело к тому, что более 30% времени CPU буксовал на 
атомарных операциях. Так что аккруатнее с желаниями, они могут сбыться ;)
Иван Леваше
Re: Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-11-06 20:44:17
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
Dmitriy Anisimkov
Re: [ada_ru] Что одним аскетизм, то другим геморрой (про счётчики ссылок)
2016-11-07 02:53:30
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);
Новое сообщение:
Страницы: 1

Чтобы оставить новое сообщение необходимо Зарегистрироваться и Войти