Comments 66
Нагребатор(tm) и разгребатор(tm) — это сильно!
Главное корень слов правильно понять и не путать как некоторые переводчики англоязычных фильмов.
Главное корень слов правильно понять и не путать как некоторые переводчики англоязычных фильмов.
+11
даёшь правильный перевод парадигмы producer-consumer
0
Поставщик — потребитель?
+1
Это когда producer лениво и неторопливо генерирует 10 сообщений в минуту — тогда да, тогда он производитель. А когда 10 000 в секунду — тогда какой же он производитель, разве можно что-то с такой скоростью производить? — Он нагребатор, как есть нагребатор.
В данном примере нагребатор/разгребатор гораздо более яркая и говорящая метафора. И не только в данном, как показывает практика )
В данном примере нагребатор/разгребатор гораздо более яркая и говорящая метафора. И не только в данном, как показывает практика )
+3
Нагрузочный тест — нагибатор…
+7
Резонно к этим всем качествам добавить ещё и свойство garbage less.
…
нужны только самые актуальные — то хорошо бы хранить пары ключ-значение в некотором ассоциативном массиве, перетирая старые значения новыми
А это как тогда друг с другом коррелирует?
А вообще, в статье слишком уж сжато начинается с Card Mark'а, неговоря уже про отсылки к D., которые понять можно только побывав (или почитав) на докладе у Руслана. Если будет время/желания, для увеличения читаемости можете поподробнее раскрыть эти моменты.
+2
Card Mark — это ухищрение для второго пунтка общего дизайна (бежать по ассоциативному массиву, забирать самые свежие значения и отдавать в обработчик).
Т.е без card mark обработка задач происходила бы как
Что как-то нелепо — зачем сканировать область массива, которая никак не изменялась. Но сам по себе card mark не связан с Disruptor.
Пожалуй, ключевая отсылка к D. это идея waiting strategy.
Т.е без card mark обработка задач происходила бы как
for(int i = 0; i < values.length; i++){
V value = values[i].getAndSet(null);
if (value != null){
processor.handle(value);
}
}
Что как-то нелепо — зачем сканировать область массива, которая никак не изменялась. Но сам по себе card mark не связан с Disruptor.
Пожалуй, ключевая отсылка к D. это идея waiting strategy.
0
Ну этот CardMark — это не dirty memory regions card marking, который используется GC, и про который я мог рассказывать (правда я сам уже не помню, когда и где я про него рассказывал). Но да, здесь та же самая идея, только в собственноручном исполнении
+1
UFO just landed and posted this here
wait strategy с busy-spin-ом и сотней попыток выбирался исходя из оценочного количества входящих сообщений в реальной системе.
согласен, что на холодных нитках latency будут далеко не такими хорошими, как в приведённых графиках — можно придумать какого-нибудь мутанта, который после нескольких неудачных попыток захватить по busy-spin вообще переставал так делать (аналогия между thin/fat locks), но это уже отдельный вопрос
согласен, что на холодных нитках latency будут далеко не такими хорошими, как в приведённых графиках — можно придумать какого-нибудь мутанта, который после нескольких неудачных попыток захватить по busy-spin вообще переставал так делать (аналогия между thin/fat locks), но это уже отдельный вопрос
0
UFO just landed and posted this here
Верное замечание.
Проблема в том, что я не знаю, что есть такое «обычное приложение».
В случае еле-еле идущего потока может быть нужна другая реализация (использующая обычный wait/notify) wait strategy или как вариант вообще обрабатывать сообщения на нитке нагребатора.
Словом, это не универсальное решение типа кухонного комбайна.
Проблема в том, что я не знаю, что есть такое «обычное приложение».
В случае еле-еле идущего потока может быть нужна другая реализация (использующая обычный wait/notify) wait strategy или как вариант вообще обрабатывать сообщения на нитке нагребатора.
Словом, это не универсальное решение типа кухонного комбайна.
0
Мне кажется, разница упрется в реализацию waitStrategy. От оптимизации структур данных, избавления от блокировок и аллокаций на fast-path вряд ли кому станет хуже, хотя кто-то, конечно, может и не заметить разницы.
Тут есть еще ценность в самом интерфейсе, в API — я в своей жизни видел дюжину реализаций подобного троллинга, и там обычно было месиво разных примитивов синхронизации с неочевидным API и неочевидным же контрактом. Здесь как раз можно сформулировать вменяемое компактное апи с компактным же контрактом (правда, про апи-то Володя как раз не написал)
Тут есть еще ценность в самом интерфейсе, в API — я в своей жизни видел дюжину реализаций подобного троллинга, и там обычно было месиво разных примитивов синхронизации с неочевидным API и неочевидным же контрактом. Здесь как раз можно сформулировать вменяемое компактное апи с компактным же контрактом (правда, про апи-то Володя как раз не написал)
0
Я изыскивыаю возможности открыть код, так, чтобы он не противоречил условиям контракта. Трудового. Моего.
+1
UFO just landed and posted this here
Почему же это каждом велосипеде — мы как раз обточивая конкретное решение хотим сократить количество других велосипедов одним.
Конечно, ни я, ни Руслан не знаем внутренний мир реализации JVM как знаете его Вы и какие финты и оптимизации может сделать JVM. Это кстати один из пунктов, который сильно удивил меня в случае реализации на AtomicArrayRefs + BinaryHeapCardMark — ожидания говорили одно, а на деле вышло совсем иное.
Опять же — это ни в коем случае не пропадаганда common case для работы на миллионах разных машин с разными архитектурами. И именно поэтому вынесли на суд общественности — здравая критика приветсвуется, только не ногами по голове.
Конечно, ни я, ни Руслан не знаем внутренний мир реализации JVM как знаете его Вы и какие финты и оптимизации может сделать JVM. Это кстати один из пунктов, который сильно удивил меня в случае реализации на AtomicArrayRefs + BinaryHeapCardMark — ожидания говорили одно, а на деле вышло совсем иное.
Опять же — это ни в коем случае не пропадаганда common case для работы на миллионах разных машин с разными архитектурами. И именно поэтому вынесли на суд общественности — здравая критика приветсвуется, только не ногами по голове.
0
А что там ты ожидаешь с холодными нитками — я пока не понял идеи?
Мое личное мнение, честно говоря, что в данном случае метрика «время от входа до выхода» вообще не является репрезентативной, потому что на нее, начиная с какой-то степени оптимизированности, гораздо больше влияют тонкости thread scheduling-а, чем уже наши оптимизации. То есть мы больше измеряем взаимодействие waitStrategy с thread scheduler-ом, чем например, оптимальность раскладки наших данных в памяти.
С моей точки зрения подходящие метрики здесь это
а) GC-less — количество создаваемого мусора
б) время .put() — задержки, которые мы вносим в потоки-нагребаторы
в) время сканирования в разгребаторах — тут возникает несколько метрик, типа относительного объема «холостых» операций по отношению к полезным, и отдельно стоимость холостого сканирования и стоимость сканирования с реально обнаруженными изменениями
Мое личное мнение, честно говоря, что в данном случае метрика «время от входа до выхода» вообще не является репрезентативной, потому что на нее, начиная с какой-то степени оптимизированности, гораздо больше влияют тонкости thread scheduling-а, чем уже наши оптимизации. То есть мы больше измеряем взаимодействие waitStrategy с thread scheduler-ом, чем например, оптимальность раскладки наших данных в памяти.
С моей точки зрения подходящие метрики здесь это
а) GC-less — количество создаваемого мусора
б) время .put() — задержки, которые мы вносим в потоки-нагребаторы
в) время сканирования в разгребаторах — тут возникает несколько метрик, типа относительного объема «холостых» операций по отношению к полезным, и отдельно стоимость холостого сканирования и стоимость сканирования с реально обнаруженными изменениями
0
UFO just landed and posted this here
Давайте определимся: постановка задачи предполагает высоконагруженную систему и в силу этого скорее интересует the best и average case.
В случае же с теми решениями, которые были ранее — лучше ровного распредления от 0 до 300 мкс даже на самых разогретых нитках не получалось.
В случае же с теми решениями, которые были ранее — лучше ровного распредления от 0 до 300 мкс даже на самых разогретых нитках не получалось.
0
Ну возможно. Я и говорю — от входа до выхода это скорее синтетический тест всей системы (включая планировщик задач). А вот микробенчмарки отдельных ее частей были бы, строго говоря, более репрезентативны — но только для тех, кто сможет их в уме скомбинировать ) С точки зрения краткого описания синтетический бенчмарк более понятно выглядит — хотя комментарии насчет «у нас особые условия, не пытайтесь повторить их без участия профессионалов» вполне уместны )
0
Интересно узнать про магию AtomicReferenceUpdater'а, в чём она проявляется в данном случае?
0
Это для красного словца — никакой магии сверх той, что описана в спецификации AtomicXXXUpdater (т.е. возможность делать CAS/lazySet через reflection на волатильных полях без создания объектов AtomicXXX) здесь не используется.
0
UFO just landed and posted this here
резонно, спасибо. сделаем, опубликуем
0
+1 за «нагибатор» вместо «нагребатора»
И ещё предлагаю на пару с ThrottlingExecutor завести Троллинг Экзекьютор!
И ещё предлагаю на пару с ThrottlingExecutor завести Троллинг Экзекьютор!
+2
И у меня похожий велосипед, только разгребаторам выделяются таски по ряду дополнительных критериев.
0
Интересно. И как вы решаете данную проблему? Какие у вас ограничения?
+1
В данном случае реализация на NodeJS. Соответственно проблема многопоточности отпадает в связи с архитектурой платформы (workflow асинхронный, но все выполняется в одном потоке, многопоточность симулируется). Временной интервал для задач варьируется в интервале от нескольких секунд до нескольких минут.
Критерии для обработчиков — типы задач (множество) и интервал приоритетов.
В моем случае потери на скорости распределения ничтожны по сравнению с длительностью выполнения задач, дополнительная оптимизация не требовалась, более важным фактором была гибкость в настройке / диапазон возможных критериев и понимание пользователями принцыпа работы.
Критерии для обработчиков — типы задач (множество) и интервал приоритетов.
В моем случае потери на скорости распределения ничтожны по сравнению с длительностью выполнения задач, дополнительная оптимизация не требовалась, более важным фактором была гибкость в настройке / диапазон возможных критериев и понимание пользователями принцыпа работы.
0
Кстати, пообщаться на эту и другие темы со мной и другими троллями, такими как Руслан и Алексей можно будет на 5го апреля на конференции javapoint в Питере.
+1
UFO just landed and posted this here
Хочется и твой доклад послушать, и доклад Руслана — а судя по всему вы будите в параллель — может быть кто из организаторов javapoint сможет уточнить этот момент. И так же то — будет ли видеозапись докладов или нет?
И разве кто спорит, что написание бенчмарков и вообще проведение измерений и единственно верная их трактовка это не искусство?
И разве кто спорит, что написание бенчмарков и вообще проведение измерений и единственно верная их трактовка это не искусство?
0
Да, про видеозапись поддержу. Можно даже как на javazone: материалы только для участников.
0
ну на счет " материалы только для участников." я бы хотел задать встречный вопрос: а как же быть тем кто не в питере?
С одной стороны интересная конференция, с другой в апреле-мае пройдут java one, javaee, jpoint, где доклады частично пересекаются, на все не съездишь если ты не в питере-москве живешь, а так хоть видео можно было бы посмотреть тех докладов которые не видел.
С одной стороны интересная конференция, с другой в апреле-мае пройдут java one, javaee, jpoint, где доклады частично пересекаются, на все не съездишь если ты не в питере-москве живешь, а так хоть видео можно было бы посмотреть тех докладов которые не видел.
0
ну на счет " материалы только для участников." я бы хотел задать встречный вопрос: а как же быть тем кто не в питере?
Конфа платная, соответственно если вы купили билет — вам и запись. Нет билета — нет записи. Если записи раздавать всем после конфы — зачем покупать билет тогда, а тогда конфы не будет по финансовым соображениям.
-3
всегда считал конференции в первую очередь пиаром, но уж никак не способом заработка
для того и спонсоры чтобы покрыть разницу в бюджете между билетами проданными и стоимостью организации
вопрос в том, что для некоторых с учетом билетов и жилья стоимость конференций получается отнють не такой какая она стоит на сайте, а можно смело суммарные траты умножать на 5 от стоимости билета и брать отпуск/отгулы на 2-3 дня минимум
покупать записи за стоимость участия это вообще больше попахивает бредом, а со скидкой следуя вашей логике продавать тоже не стоит
для того и спонсоры чтобы покрыть разницу в бюджете между билетами проданными и стоимостью организации
вопрос в том, что для некоторых с учетом билетов и жилья стоимость конференций получается отнють не такой какая она стоит на сайте, а можно смело суммарные траты умножать на 5 от стоимости билета и брать отпуск/отгулы на 2-3 дня минимум
покупать записи за стоимость участия это вообще больше попахивает бредом, а со скидкой следуя вашей логике продавать тоже не стоит
+1
Кстати, Владимир, на прошлой или позапрошлой J1 я у вас спрашивал после доклада о GC free логгере, связывались ли вы с ребятами из Logback по поводу полученных результатов.
Я смотрю, вы снова выступаете с тем же докладом — как за год/два прогресс у Logback в плане перфоманса и у вас в плане коммуникаций с девелоперами? )
Я смотрю, вы снова выступаете с тем же докладом — как за год/два прогресс у Logback в плане перфоманса и у вас в плане коммуникаций с девелоперами? )
0
А не лучше, если приходит задание типа А, а в вашем хеш-хранилище актуальных заданий по типам было пусто для типа A (сделать какой-нибудь getAndSet), то тип положить в очередь тип A. Пусть разгребатор просто берет типы из готовы очереди. Очередь, видимо, лучше сделать на базе кольцевого массива с типичной стратегией удвоения как вы все-равно делаете для хеш-таблицы.
0
Намного чаще встречается задачка, когда нельзя в момент провисаний по загрузке нельзя просто схлопывать по ключу. А когда нужно иногда схлопывать, а иногда чтото более умное делать. Вот на эту тему написал я недавне штуку под названием ActiveThrottlingQueue. Работает по принципу очереди событий, когда парсинг событий делится на 2 части, быстрая загрузка событий в локальный структуры и мапы, а затем груповая работа по обработке изменений.
0
>нагибатор/нагребатор
У меня дежавю или я с ума схожу — какое-то время назад как будто уже читал эту статью… и главное как будто даже комментарии по поводу терминологии такие же были
У меня дежавю или я с ума схожу — какое-то время назад как будто уже читал эту статью… и главное как будто даже комментарии по поводу терминологии такие же были
0
Я тоже немного занимался задачей троттлинга (мы из одного домена, если вы меня не знаете :) ). Реальное использование выявило такой кейс: таска, которая кидается в executor может блокироваться, а апдейты на данное значение продолжают сыпаться. Есть какие-нибудь идеи насчет API для этого кейса? Я выкрутился тем, что обернул каждое сообщение в провайдер, который по запросу элемента возвращает самое актуально значение.
0
Не совсем понял ваш случай — мы после того как вынули значение и передали его на выполнение уже никак не можем прервать её выполнение. И пока она выполняется, конечно же, другие всё новые и новые значения могут приходить, только выполнены они будут в следующую итерацию.
0
Сгребатор от LMAX: The Coalescing Ring Buffer.
Структура данных типична для Disruptor: кольцевой буффер.Из отличительных особенностей:
— доступны исходники уже сейчас
— сохранение порядка обратки сообщения в зависимости от его прихода
— только один нагребатор (тм) и один разгребатор (тм)
— нет wait-strategy для разгребатора
— есть маленькая ненулевая вероятность, что разгребатор увидит дупликаты
p.s. у меня нет выбора, чтобы не открыть свои исходники
Структура данных типична для Disruptor: кольцевой буффер.Из отличительных особенностей:
— доступны исходники уже сейчас
— сохранение порядка обратки сообщения в зависимости от его прихода
— только один нагребатор (тм) и один разгребатор (тм)
— нет wait-strategy для разгребатора
— есть маленькая ненулевая вероятность, что разгребатор увидит дупликаты
p.s. у меня нет выбора, чтобы не открыть свои исходники
0
Прочитал статью и комменты, и не понимаю — это какая-то специальная Java для посвященных? И если не знаешь, кто такой Руслан или D., то вход в элитный отряд закрыт?
В целом, пока вижу сферического коня в вакууме. Что дает измерение задержки executor-а? Каким образом оно меряется, в каких точках? Производительность нельзя рассматривать в отрыве от задачи. Что важнее — количество обработанных событий в секунду/день/год, или минимальная пиковая задержка? А если есть ограничение по задержке — скажем, опоздали на 5 секунд и событие уже не актуально, более того, можно потерять деньги, если его обработать?
Выгоднее ли потратить свое время на велосипед и на его поддержку, чем взять простой HashMap + BlockingQueue + купить 4 сервера?
В целом, пока вижу сферического коня в вакууме. Что дает измерение задержки executor-а? Каким образом оно меряется, в каких точках? Производительность нельзя рассматривать в отрыве от задачи. Что важнее — количество обработанных событий в секунду/день/год, или минимальная пиковая задержка? А если есть ограничение по задержке — скажем, опоздали на 5 секунд и событие уже не актуально, более того, можно потерять деньги, если его обработать?
Выгоднее ли потратить свое время на велосипед и на его поддержку, чем взять простой HashMap + BlockingQueue + купить 4 сервера?
0
>купить 4 сервера?
Ну наверное действительно, если вам задача позволяет просто поставить больше серверов, то наверное статья не для вас. А если интересоваться темой оптимизаций в java, то ИМХО не знать что такое D. довольно странно. Ну и лекторов по данной тематике не знать тоже.
Ну наверное действительно, если вам задача позволяет просто поставить больше серверов, то наверное статья не для вас. А если интересоваться темой оптимизаций в java, то ИМХО не знать что такое D. довольно странно. Ну и лекторов по данной тематике не знать тоже.
0
Прошу меня простить, темой я интересуюсь, но лекторов или D. не знаю. В Питер ездить на конференции не имею возможности. Но вы опубликовали статью на хабре, значит — для всех, а не только для избранных. Отсюда и вопросы.
Я так понимаю, вы же реальные данные от третьих источников обрабатываете? Насколько я помню, в DB пишут трейдинговую систему, и данные идут из NY? Если я правильно вас погуглил.
Что дает измерение задержки executor-а на маленьких тасках? Надежней мерять не маленькие интервалы и суммировать, а нагрузить приложение реальными данными (или похожими на реальные) и измерять количество данных в час/день/неделю — эта величина коррелирует с latency. Плюс нужен тест на простой реализации, для сравнения. Ну или для смелых — сравнить прибыль в $$$ :)
Я так понимаю, вы же реальные данные от третьих источников обрабатываете? Насколько я помню, в DB пишут трейдинговую систему, и данные идут из NY? Если я правильно вас погуглил.
Что дает измерение задержки executor-а на маленьких тасках? Надежней мерять не маленькие интервалы и суммировать, а нагрузить приложение реальными данными (или похожими на реальные) и измерять количество данных в час/день/неделю — эта величина коррелирует с latency. Плюс нужен тест на простой реализации, для сравнения. Ну или для смелых — сравнить прибыль в $$$ :)
0
Прочитал статью и комменты, и не понимаю — это какая-то специальная Java для посвященных? И если не знаешь, кто такой Руслан или D., то вход в элитный отряд закрыт?
Нет, это просто Java. Просто без EE.
Насколько я помню, в DB пишут трейдинговую систему, и данные идут из NY? Если я правильно вас погуглил.
Нет, не верно, данные идут с локальных бирж (или локальных точек присутствия бирж и это не только из Нью Йорка, это прежде всего Лондон, Токио, Сингапур.
Что дает измерение задержки executor-а на маленьких тасках
Время прохождения через executor, т.е. какова величина накладных расходов, которые даёт сам executor. Разумеется, что мы измеряем производительность системы целиком, но в то же время меряем и производительность отдельных компонент, в т.ч. и используя синтетические тесты.
Выгоднее ли потратить свое время на велосипед и на его поддержку, чем взять простой HashMap + BlockingQueue + купить 4 сервера?
Нет, задача не масштабирования уровня обработать 10000 и 1 запрос, когда каждый из них будет обрабатываться 100 мс — вопрос в том, что каждый запрос должен быть обработан как можно быстрее, в так называемом sub millisecond latency.
0
Время прохождения через executor, т.е. какова величина накладных расходов, которые даёт сам executor
А, теперь понятна цель. Не ясно, каким образом это измеряется. Перед помещением задачи в executor вызывается System.nanoTime(), это значение передается в таск, а в нем опять вызывается nanoTime() и считается разница? А результат в отдельный поток?
Это я к тому, что по количеству обработанных задач в некий промежуток времени можно оценить накладные расходы более точно, чем считать время в каждом таске.
Нет, задача не масштабирования уровня обработать 10000 и 1 запрос, когда каждый из них будет обрабатываться 100 мс — вопрос в том, что каждый запрос должен быть обработан как можно быстрее,
Понял.
0
Как показал мой опыт (тут ожидаю появление джина) nanoTime не самый лучший способ измерения времени между потоками, мы используем некоторый свой jni вызов, который возвращает системное время в нс — немного об этом у меня в блоге.
Результат измерения latency складывается в массив на потоке разгребатора, где уже по окончании уже он забирается целиком.
Если сильно упрощённо, то
Результат измерения latency складывается в массив на потоке разгребатора, где уже по окончании уже он забирается целиком.
Если сильно упрощённо, то
final long[] times = new long[5000];
// .....
final long diffUs = nowUs() - event.timeUs;
times[diffUs]++;
//
0
Да, помню статью про RDTSC на хабре. А зачем брать CLOCK_REALTIME, для измерения задержки достаточно ведь MONOTONIC? Там, конечно, полно всякого кода, но CLOCK_REALTIME его же и вызывает, плюс еще и wall clock читает. Могу ошибаться, исходники ядра давно ковырял.
0
Решение используется не только для оценки задержки внутри одной JVM, но и для оценки latency между компонентами на разных серверах — всё равно jni библиотеку делать и подключать, а разница между CLOCK_REALTIME и MONOTONIC не столь критичная. Хотя, можно вынести как отдельный метод для специальных случаев.
Конечно же, в этом случае, мы передаём мкс, а не нс.
Конечно же, в этом случае, мы передаём мкс, а не нс.
+1
>Это я к тому, что по количеству обработанных задач в некий промежуток времени можно оценить накладные расходы более точно, чем считать время в каждом таске.
Какие именно накладные расходы можно оценить «более точно»? Чтобы говорить то, что вы говорите, нужно иметь в голове некую модель того, что происходит в системе, и что именно мы хотим измерить. Измеряя количество задач в единицу времени вы тестируете систему в режиме насыщения — в этом режиме вы можете упираться в совершенно другие узкие места, чем упирается время ответа в ненасыщенном режиме.
Например, в ненасыщенном режиме у вас «стоимость» CAS-а (внутри put)будет примерно постоянной, потому что contention будет низким, и вероятность неуспешного CAS-а тоже будет низкой. Зато будет важна эффективность работы CardMarking-а — потому что в среднем таблица будет едва-едва заполненной, и сканировать ее целиком каждый раз будет не эффективно, и CardMarking тут очень к месту.
А в режиме насыщения CardMarking будет только мешаться, потому что таблица скорее всего будет заполнена, и толку от CardMarking будет мало, а накладные расходы он вносит. С другой стороны, стоимость CAS-а вырастет (поскольку вырастет contention), и начнет заметно зависеть от всяких деталей компоновки объектов в памяти, и количество неуспешных CAS-ов тоже вырастет, и поэтому будет важна реализация backoff после неудавшихся CAS-ов.
Это так, навскидку описание. Все может быть иначе, и вообще дракон из монитора вылезет и откусит экспериментатору голову.
Для нашей конкретной задачи нужно минимальное время доставки до обработчика каждого конкретного таска. Предельная пропускная способность нас интересует гораздо меньше — у нас система даже близко не подходит к режиму насыщения. Поэтому эксперимент поставлен так, как поставлен. «Плюнь тому в глаза, кто скажет, что можно обнять необъятное!»
Какие именно накладные расходы можно оценить «более точно»? Чтобы говорить то, что вы говорите, нужно иметь в голове некую модель того, что происходит в системе, и что именно мы хотим измерить. Измеряя количество задач в единицу времени вы тестируете систему в режиме насыщения — в этом режиме вы можете упираться в совершенно другие узкие места, чем упирается время ответа в ненасыщенном режиме.
Например, в ненасыщенном режиме у вас «стоимость» CAS-а (внутри put)будет примерно постоянной, потому что contention будет низким, и вероятность неуспешного CAS-а тоже будет низкой. Зато будет важна эффективность работы CardMarking-а — потому что в среднем таблица будет едва-едва заполненной, и сканировать ее целиком каждый раз будет не эффективно, и CardMarking тут очень к месту.
А в режиме насыщения CardMarking будет только мешаться, потому что таблица скорее всего будет заполнена, и толку от CardMarking будет мало, а накладные расходы он вносит. С другой стороны, стоимость CAS-а вырастет (поскольку вырастет contention), и начнет заметно зависеть от всяких деталей компоновки объектов в памяти, и количество неуспешных CAS-ов тоже вырастет, и поэтому будет важна реализация backoff после неудавшихся CAS-ов.
Это так, навскидку описание. Все может быть иначе, и вообще дракон из монитора вылезет и откусит экспериментатору голову.
Для нашей конкретной задачи нужно минимальное время доставки до обработчика каждого конкретного таска. Предельная пропускная способность нас интересует гораздо меньше — у нас система даже близко не подходит к режиму насыщения. Поэтому эксперимент поставлен так, как поставлен. «Плюнь тому в глаза, кто скажет, что можно обнять необъятное!»
0
>Надежней мерять не маленькие интервалы и суммировать, а нагрузить приложение реальными данными (или похожими на реальные) и измерять количество данных в час/день/неделю — эта величина коррелирует с latency.
Надежнее всего, на мой взгляд, не думать, что есть единственно правильный метод измерять что либо. Есть безусловно место и для синтетических бенчмарков всего приложения в целом. Но если вы не представляете что происходит в вашей системе на уровне отдельных ее компонент, вы не сможете правильно интерпретировать эти синтетические бенчмарки. Что толку знать, что у вас полное время ответа 100мс, когда надо 20, а вы не представляете как можно хотя бы один из этапов обработки сделать быстрее 50мс, потому что складывая пасьянс из стандартных примитивов быстрее не сделать?
>Что дает измерение задержки executor-а на маленьких тасках?
Интерпретация _любых_ бенчмарков требует аккуратности и опыта. Ложные выводы можно сделать как из результатов синтетических тестов «в $$$», так и из результатов микробенчмарков в микросекундах.
Надежнее всего, на мой взгляд, не думать, что есть единственно правильный метод измерять что либо. Есть безусловно место и для синтетических бенчмарков всего приложения в целом. Но если вы не представляете что происходит в вашей системе на уровне отдельных ее компонент, вы не сможете правильно интерпретировать эти синтетические бенчмарки. Что толку знать, что у вас полное время ответа 100мс, когда надо 20, а вы не представляете как можно хотя бы один из этапов обработки сделать быстрее 50мс, потому что складывая пасьянс из стандартных примитивов быстрее не сделать?
>Что дает измерение задержки executor-а на маленьких тасках?
Интерпретация _любых_ бенчмарков требует аккуратности и опыта. Ложные выводы можно сделать как из результатов синтетических тестов «в $$$», так и из результатов микробенчмарков в микросекундах.
0
— взять простой HashMap + BlockingQueue
Можно, только в этом случае очередь будет расти. Более того, все последующие ключи в очереди по-сути уже будут не нужны — т.к. самое актуальное значение будет удалено из HashMap-ы при первом же обращении по ключу.
Второй момент — это доп. расходы на поддержание обеих структур — расход по памяти, (cache locality), атомарность, видимость значений.
И третий момент — 4 сервера исходя из каких соображений? Из тех, что пишем код как получится, а после закидываем шапками?
Можно, только в этом случае очередь будет расти. Более того, все последующие ключи в очереди по-сути уже будут не нужны — т.к. самое актуальное значение будет удалено из HashMap-ы при первом же обращении по ключу.
Второй момент — это доп. расходы на поддержание обеих структур — расход по памяти, (cache locality), атомарность, видимость значений.
И третий момент — 4 сервера исходя из каких соображений? Из тех, что пишем код как получится, а после закидываем шапками?
0
Можно, только в этом случае очередь будет расти
Можно сделать так:
previousValue = concurrentHashMap.put(key, newValue)
if (value!=null) {
queue.add(...);
}
Ну и забирать через put(key, null)
4 сервера были взяты с потолка.
В целом, ваша задача понятна. Я вообще начал этот тред т.к. зацепился за фразу «типичная проблема в большом классе задач». В процессе обсуждения оказалось, что задача специфическая, с известными рамками.
0
Фраза звучит примерно так:
«типичная проблема в большом классе задач в алчном нашем мире борьбы за то кто кого быстрее обманет, продавая валюту»
Хорошо, это вы решаете проблему нерастущей очереди.
Один из самых больших выигрышей (в нашем случае, и быть может в случае других алчных задач) даёт как раз использование wait strategy, в сравнении с использованием wait/notify. Это ответ почему не BlockingQueue.
И в финале решили объединить только самое необходимое из двух структур в одно.
«типичная проблема в большом классе задач в алчном нашем мире борьбы за то кто кого быстрее обманет, продавая валюту»
Можно сделать так:
previousValue = concurrentHashMap.put(key, newValue)
if (previousValue != null) {
queue.add(...);
}
Ну и забирать через put(key, null)
Хорошо, это вы решаете проблему нерастущей очереди.
Один из самых больших выигрышей (в нашем случае, и быть может в случае других алчных задач) даёт как раз использование wait strategy, в сравнении с использованием wait/notify. Это ответ почему не BlockingQueue.
И в финале решили объединить только самое необходимое из двух структур в одно.
+1
Начальный вариант кода открыт:
https://bitbucket.org/vladimir.dolzhenko/collections/
Пока это только реализация на массиве atomic reference с простым card mark.
https://bitbucket.org/vladimir.dolzhenko/collections/
Пока это только реализация на массиве atomic reference с простым card mark.
0
Sign up to leave a comment.
Articles
Change theme settings
Java: executor с уплотнением по ключам