Сообщение Re[24]: Эльбрус мёртв, да здравствует Эльбрус-Б! от 03.06.2025 6:53
Изменено 03.06.2025 7:14 vdimas
Re[24]: Эльбрус мёртв, да здравствует Эльбрус-Б!
Здравствуйте, Sinclair, Вы писали:
S>Прикол-то в том, что если изначально идти по пути "давайте просто будем складывать объекты в однопоточную queue, а доступ к самой очереди и к данным лежащих в ней объектов рулить при помощи примитивов синхронизации", то никакие выравнивания не помогут.
Что тоже неверно, т.к. банальный прикладной мьютекс что в WinAPI (CriticalSection) что в Pthreads дергает семафор только в случае конфликтов, а в отсутствии оных всё ограничивается парой CAS: при захвате ресурса и при отпускании. И да, рекурсивный мьютекс чуть дороже, т.к. должен еще прочитать текущий thread id, а нерекурсивный пользует обычные флаги 1-0.
S>И никакие аппаратные улучшения тоже не помогут.
Еще как помогут, ведь операция над семафором — это тоже один CAS в контексте исполнения ядра, блокирующее ожидание — пара CAS на очереди ожидания и один на шедуллере.
Другое дело, что сами системные вызовы дороги в современной системе защиты памяти из-за смены контекста исполнения, из-за этого же дороги переключения логических потоков на аппаратных, т.е. снять поток уровня ОС и поставить его на исполнение в современном мейнстриме очень дорого. но при этом дешево сделать то же самое в зеленых потоках в случае stackful, т.е. без смены контекста исполнения.
S>Этот подход порочен изначально.
Это нормальный подход. Например, в одноядерной системе с вытеснением памяти этот подход дешевле большинства других подходов. А в кооперативной многозадачности без защиты памяти отродясь самый дешевый, поэтому эту кооперативную многозадачность и реализуют в зеленых потоках и прочей дотнетной асинхронщине (и тоже без взаимной защиты памяти потоков внутри одного процесса, ес-но).
S>Примерно как пытаться делать HTTP-сервер на честных аппаратных потоках, создаваемых на каждый сокет.
Но это хорошо работает в кооперативной многозадачности. ))
S>И отдельно хочется отметить, что унизительный код Disruptor с выравниваниями связан с особенностями именно Java — дотнет предоставляет гораздо более прямые и лаконичные возможности по управлению выравниванием, см. https://github.com/disruptor-net/Disruptor-net/blob/master/src/Disruptor/Sequence.cs
О чём я и говорил, что приходится размечать вручную.
И ты привёл правильную ссылку, показывающую, что "зазор" надо делать с двух сторон в отсутствии возможности выравнивания объекта на границе адреса кеш-линии при выделении памяти под этот объект, т.е. что я и говорил — получаем перерасход памяти. Более того, этот счётчик пришлось сделать как class, т.е. выделить из GC-кучи, опять же по соображениям достоверного выравнивания. А почему так? Наверно, чтобы не возиться с выравниванием аналогичных полей при агрегировании этого счётчика в объекты более высокого уровня. Т.е., повторное использование кода у них облагается штрафом на одну косвенность. Ну тоже детсад, ес-но, потому что это ОЧЕНЬ внутренний код и можно было бы этот счётчик в отдельный класс не выделять, конечно.
S>Прикол-то в том, что если изначально идти по пути "давайте просто будем складывать объекты в однопоточную queue, а доступ к самой очереди и к данным лежащих в ней объектов рулить при помощи примитивов синхронизации", то никакие выравнивания не помогут.
Что тоже неверно, т.к. банальный прикладной мьютекс что в WinAPI (CriticalSection) что в Pthreads дергает семафор только в случае конфликтов, а в отсутствии оных всё ограничивается парой CAS: при захвате ресурса и при отпускании. И да, рекурсивный мьютекс чуть дороже, т.к. должен еще прочитать текущий thread id, а нерекурсивный пользует обычные флаги 1-0.
S>И никакие аппаратные улучшения тоже не помогут.
Еще как помогут, ведь операция над семафором — это тоже один CAS в контексте исполнения ядра, блокирующее ожидание — пара CAS на очереди ожидания и один на шедуллере.
Другое дело, что сами системные вызовы дороги в современной системе защиты памяти из-за смены контекста исполнения, из-за этого же дороги переключения логических потоков на аппаратных, т.е. снять поток уровня ОС и поставить его на исполнение в современном мейнстриме очень дорого. но при этом дешево сделать то же самое в зеленых потоках в случае stackful, т.е. без смены контекста исполнения.
S>Этот подход порочен изначально.
Это нормальный подход. Например, в одноядерной системе с вытеснением памяти этот подход дешевле большинства других подходов. А в кооперативной многозадачности без защиты памяти отродясь самый дешевый, поэтому эту кооперативную многозадачность и реализуют в зеленых потоках и прочей дотнетной асинхронщине (и тоже без взаимной защиты памяти потоков внутри одного процесса, ес-но).
S>Примерно как пытаться делать HTTP-сервер на честных аппаратных потоках, создаваемых на каждый сокет.
Но это хорошо работает в кооперативной многозадачности. ))
S>И отдельно хочется отметить, что унизительный код Disruptor с выравниваниями связан с особенностями именно Java — дотнет предоставляет гораздо более прямые и лаконичные возможности по управлению выравниванием, см. https://github.com/disruptor-net/Disruptor-net/blob/master/src/Disruptor/Sequence.cs
О чём я и говорил, что приходится размечать вручную.
И ты привёл правильную ссылку, показывающую, что "зазор" надо делать с двух сторон в отсутствии возможности выравнивания объекта на границе адреса кеш-линии при выделении памяти под этот объект, т.е. что я и говорил — получаем перерасход памяти. Более того, этот счётчик пришлось сделать как class, т.е. выделить из GC-кучи, опять же по соображениям достоверного выравнивания. А почему так? Наверно, чтобы не возиться с выравниванием аналогичных полей при агрегировании этого счётчика в объекты более высокого уровня. Т.е., повторное использование кода у них облагается штрафом на одну косвенность. Ну тоже детсад, ес-но, потому что это ОЧЕНЬ внутренний код и можно было бы этот счётчик в отдельный класс не выделять, конечно.
Re[24]: Эльбрус мёртв, да здравствует Эльбрус-Б!
Здравствуйте, Sinclair, Вы писали:
S>Прикол-то в том, что если изначально идти по пути "давайте просто будем складывать объекты в однопоточную queue, а доступ к самой очереди и к данным лежащих в ней объектов рулить при помощи примитивов синхронизации", то никакие выравнивания не помогут.
Что тоже неверно, т.к. банальный прикладной мьютекс что в WinAPI (CriticalSection) что в Pthreads дергает семафор только в случае конфликтов, а в отсутствии оных всё ограничивается парой CAS: при захвате ресурса и при отпускании. И да, рекурсивный мьютекс чуть дороже, т.к. должен еще прочитать текущий thread id, а нерекурсивный пользует обычные флаги 1-0.
S>И никакие аппаратные улучшения тоже не помогут.
Еще как помогут, ведь операция над семафором — это тоже один CAS в контексте исполнения ядра, блокирующее ожидание — пара CAS на очереди ожидания и один на шедуллере.
Другое дело, что сами системные вызовы дороги в современной системе защиты памяти из-за смены контекста исполнения, из-за этого же дороги переключения логических потоков на аппаратных ядрах, т.е. снять поток уровня ОС и поставить его на исполнение в современном мейнстриме очень дорого. Но при этом дешево сделать то же самое в зеленых потоках в случае stackful, т.е. без смены контекста исполнения.
S>Этот подход порочен изначально.
Это нормальный подход. Например, в одноядерной системе с вытеснением памяти этот подход дешевле большинства других подходов. А в кооперативной многозадачности без защиты памяти отродясь самый дешевый, поэтому эту кооперативную многозадачность и реализуют в зеленых потоках и прочей дотнетной асинхронщине (и тоже без взаимной защиты памяти потоков внутри одного процесса, ес-но).
S>Примерно как пытаться делать HTTP-сервер на честных аппаратных потоках, создаваемых на каждый сокет.
Но это хорошо работает в кооперативной многозадачности. ))
S>И отдельно хочется отметить, что унизительный код Disruptor с выравниваниями связан с особенностями именно Java — дотнет предоставляет гораздо более прямые и лаконичные возможности по управлению выравниванием, см. https://github.com/disruptor-net/Disruptor-net/blob/master/src/Disruptor/Sequence.cs
О чём я и говорил, что приходится размечать вручную.
И ты привёл правильную ссылку, показывающую, что "зазор" надо делать с двух сторон в отсутствии возможности выравнивания объекта на границе адреса кеш-линии при выделении памяти под этот объект, т.е. что я и говорил — получаем перерасход памяти. Более того, этот счётчик пришлось сделать как class, т.е. выделить из GC-кучи, опять же по соображениям достоверного выравнивания. А почему так? Наверно, чтобы не возиться с выравниванием аналогичных полей при агрегировании этого счётчика в объекты более высокого уровня. Т.е., повторное использование кода у них облагается штрафом на одну косвенность. Ну тоже детсад, ес-но, потому что это ОЧЕНЬ внутренний код и можно было бы этот счётчик в отдельный класс не выделять, конечно.
S>Прикол-то в том, что если изначально идти по пути "давайте просто будем складывать объекты в однопоточную queue, а доступ к самой очереди и к данным лежащих в ней объектов рулить при помощи примитивов синхронизации", то никакие выравнивания не помогут.
Что тоже неверно, т.к. банальный прикладной мьютекс что в WinAPI (CriticalSection) что в Pthreads дергает семафор только в случае конфликтов, а в отсутствии оных всё ограничивается парой CAS: при захвате ресурса и при отпускании. И да, рекурсивный мьютекс чуть дороже, т.к. должен еще прочитать текущий thread id, а нерекурсивный пользует обычные флаги 1-0.
S>И никакие аппаратные улучшения тоже не помогут.
Еще как помогут, ведь операция над семафором — это тоже один CAS в контексте исполнения ядра, блокирующее ожидание — пара CAS на очереди ожидания и один на шедуллере.
Другое дело, что сами системные вызовы дороги в современной системе защиты памяти из-за смены контекста исполнения, из-за этого же дороги переключения логических потоков на аппаратных ядрах, т.е. снять поток уровня ОС и поставить его на исполнение в современном мейнстриме очень дорого. Но при этом дешево сделать то же самое в зеленых потоках в случае stackful, т.е. без смены контекста исполнения.
S>Этот подход порочен изначально.
Это нормальный подход. Например, в одноядерной системе с вытеснением памяти этот подход дешевле большинства других подходов. А в кооперативной многозадачности без защиты памяти отродясь самый дешевый, поэтому эту кооперативную многозадачность и реализуют в зеленых потоках и прочей дотнетной асинхронщине (и тоже без взаимной защиты памяти потоков внутри одного процесса, ес-но).
S>Примерно как пытаться делать HTTP-сервер на честных аппаратных потоках, создаваемых на каждый сокет.
Но это хорошо работает в кооперативной многозадачности. ))
S>И отдельно хочется отметить, что унизительный код Disruptor с выравниваниями связан с особенностями именно Java — дотнет предоставляет гораздо более прямые и лаконичные возможности по управлению выравниванием, см. https://github.com/disruptor-net/Disruptor-net/blob/master/src/Disruptor/Sequence.cs
О чём я и говорил, что приходится размечать вручную.
И ты привёл правильную ссылку, показывающую, что "зазор" надо делать с двух сторон в отсутствии возможности выравнивания объекта на границе адреса кеш-линии при выделении памяти под этот объект, т.е. что я и говорил — получаем перерасход памяти. Более того, этот счётчик пришлось сделать как class, т.е. выделить из GC-кучи, опять же по соображениям достоверного выравнивания. А почему так? Наверно, чтобы не возиться с выравниванием аналогичных полей при агрегировании этого счётчика в объекты более высокого уровня. Т.е., повторное использование кода у них облагается штрафом на одну косвенность. Ну тоже детсад, ес-но, потому что это ОЧЕНЬ внутренний код и можно было бы этот счётчик в отдельный класс не выделять, конечно.