Информация об изменениях

Сообщение Re[53]: dotnet vs java 2016-2020 от 22.10.2016 17:33

Изменено 22.10.2016 17:34 vdimas

Здравствуйте, ·, Вы писали:

V>>Я не хуже тебя представляю, что там с потоками в Джава и как оно устроено. И при чем тут язык или системные библиотеки.

·>А что причём? Твоё личное мнение?

А какое тут вообще может быть мнение? ))
Программист должен уметь различать сущности языка (например "класс") и экземпляры сущностей (конкретный класс Thread).

Я хорошо понимаю причины твоего упорства, т.к. в стандарт языка Джава входит не только описание самого языка и минимальной инфраструктуры вокруг него. Однако, не надо путать одно с другим. Если уж говорить о synchronized, то, скорее, надо говорить об обязательном Мониторе в реализации инфраструктуры, чем о Thread, бо Монитор прекрасно работает даже когда мы вызываем джавовский код из потока, созданного не через джавовский класс Thread.


V>>А для борьбы с глупостью стоило посмотреть на язык go, где потоки встроены в сам язык.

·>Каким образом они там "встроены"? Судя по твоим рассужениям так же — часть библиотеки.

Из моих рассуждений следует ровно противоположное. А из твоих рассуждений следует лишь одно — ты много пишешь здесь и мало читаешь вовне. ))
Таки, посмотри на go, там на что взглянуть. Собственно, само название языка — это название конструкции по запуску нового вычислительного потока/задачи в этом языке.


V>>·>Ещё намёк — в каком пакете находится класс Thread?

V>>Плевать с большой колокольни.
·>Плюй, не плюй, а факт остаётся фактом.

Факт чего? Имени собственного пакета?


V>>·>А вот всякие сетевые сокеты, файлы, коллекции, регекспы и прочее — да, это часть стандартной библиотеки, а не языка.

V>>Я правильно понимаю, что от одного лишь имени собственного пакета "lang" у тебя малость зрение меняется?
·>А у тебя зрение меняется когда факты противоречат твоим убеждениям.

Так ты мне факты не показал еще.


V>>Треды — это отъемлимая часть аж бегом.

V>>Ты демонстрируешь тут повадки новичков в Джаве, которые на голубом глазу путают язык и VM.
·>Ну погугли что такое monitorenter/monitorexit и описание поведения других инструкций в многопоточном окружении.

Нашел что просить погуглить. Ты бы еще "мама мыла раму" попросил погуглить.

Лучше погугли железные реализации джава-машинки и что там было реализовано в железе, а что нет. И почему именно так.


V>>·>Причём тут вообще сокеты? Зачем ты упомянул их? Как они с протоколами HTTP или FIX связаны?

V>>Напрямую связаны, ес-но.
·>Нет, конечно, не связаны. Или у тебя есть какие-то доказательства?

Конечно есть. Это сетевая модель OSI.
Прямо по этой фразе и гуглить.
Собсно, в описаниях самих протоколов четко прописывается на каких уровнях модели OSI обитают эти протоколы.


V>>·>В смысле у вас только IOCP сокеты в нативе

V>>В смысле виденные мною HTTP-серваки на дотнете используют такие сетевые ср-ва (асинхронный IO), которые были разработаны в нейтиве.
·>Не путай HTTP-сервер и HTTP-протокол.

Не виляй.


·>на джаве обычно есть pure-java реализация стандартными средствами и нативные модули для работы со специфичными под конкретную систему нативными имплементациями, если есть что-то специфичное, конечно.


Бессмысленное бла-бла-бла.


V>>

V>>Стандартный цикл обращения объектов через межпоточный буфер и обратно в "пул" реализованы как две встречных очереди

V>>Тут стоило помедитировать. Это СТАНДАРТНЫЙ подход. Это, блин, сверх-мега-стандартный подход для таких вещей. Это база, уровень 0. ))
·>Где в дизрапторе происходит генерация объектов? Что ты вообще назвал генерацией объектов?

Это ты назвал, я тут причем?


V>>Две встречные очереди образуют "кольцо". Эдакие чётки, как у попа, только вместо пальцев правой и левой руки у нас производитель и потребитель. Один берет из пула объект, подготавливает его и пихает "туда". Другой обрабатывает и пихает "обратно".

·>Что-то какое-то странное представление. Обычная очередь, одна, как в ларёк за пивом. Очереди образуют кольцо?.. Брр. Как-то всё переусложнено.

Ты называешь это сложным?
ОК.


V>>Чем ring-buffer отличается от двух встречных очередей? Да ничем, кроме того, что реализован не на связанном одностороннем списке объектов, а через прибитый к реализации массив фиксированного размера, что считается самой худшей схемой из всех известных. )) Ну, кроме случая, где генерирование и потребление происходит заведомо с одинаковой скоростью,

·>Нет, когда потребление в среднем не медленнее продьюсинга.

Интересует как раз не в среднем.


V>>как при воспроизведении аудио, например. Более того, запись и чтение из кольцевого буфера на один CAS дороже, чем в стандартной схеме межпотокового буфера. Ну и, самое главное, часто мы имеем обращение к одной и той же линейке кеша из разных потоков (ядер) в такой схеме, что до 6 раз (в среднем) тормозит любую межпоточность. Ладно аудио, там десятки-сотня пакетов в секунду от силы, но для HFT это смерть. ))

·>Там в одну линейку _пишут_ только продьюсеры, консьюмеры только читают.

Это ты так расписался в отсутствии представления о "когерентности кеша"? ))

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


·>В приведённом тобой тесте было три продьюсера.


Да хоть десять для lock-free.


·>Тут уже мало что можно сделать иначе. В случае одного продьюсера дизраптор действительно раскочегаривается по полной.


Если ты работаешь в этой области, то должен знать, что во многих биржах идёт минимум 2 UDP-фида для данных и их, таки, положено слушать из РАЗНЫХ потоков в силу особенностей работы UDP. А сами пакету сваливать затем в один поток обработки. "Раскочегаренная" обычная схема на lock-free очередях даёт менее микросекунды средней задержки (чиста для инфы).


·>Собственно это как раз одно из преимуществ дизраптора, что он дружелюбен к железу, учитывает все эти кеши и прочие нумы.



Дисраптор — это роспись в нубстве. Я уже высказывал своё мнение:


V>>>>Это и есть дисраптор. Это его базовый Lego-кубик (один из 3-х, вернее, с идентичным интерфейсом).

V>>·>А доказать?
V>>Я всё доказал, пояснив общее устройство такой схемы (две встречных очереди).
·>Я не понимаю почему ты это называешь двумя очередями. В тесте на который ты привёл — очередь одна. В один конец происходит добавление, с другого конца забирают. Никакого "возвращения" нет.


V>>Я, конечно, могу ошибаться, но мне кажется, что тебя сбивает с толку именно ring buffer. Он в этой схеме вообще не причем, но кажется тебе главной деталью.

·>Конечно главная деталь.

Ну вот ты и спалился.


·>Потому что это не очередь. По ринг-буферу могут ползать сразу несколько потребителей.


Это зависит от реализации. Есть разные реализации межпоточных очередей:
(producer-consumer)
— один-один
— много-много
— один-много
— много-один

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

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


·>И их можно огораживать барьерами — потребители C и D могут отработать только после того, как отработали предыдущие A и B (притом не важно — в каком порядке — A/B или B/A). Вот тут с картиночками: http://martinfowler.com/articles/lmax.html


Да пофиг на подробности реализации. Каждая дополнительная фича в этой схеме — это дополнительные тормоза.
В стандартной "раскочегаренной" схеме где пара потоков пишет, а один читает, каждый поток-producer умудряется сделать до 30-40 млн итераций в секунду, а consumer в два раза больше.
В тесте происходит следующее:
Два потока-производителя вынимают из личного пула объект и ставят в очередь.
Поток-потребитель вынимает объект из очереди и возвращает каждый объект в его личный пул.

И тут чем меньше дополнительных операций, тем лучше, бо счет идёт на считанные единицы машинных команд на операцию.


·>Т.е. этот один единственный паттерн позволяет реализовывать довольно сложное взаимодействие между множествами тредов просто складывая их как кубики.


Паттернов много. Понятно, что "много-много" — самый универсальный, но и самый тормозной, при том, что нужен крайне редко, если включать голову.


V>>По последнему. Без ring buffer можно организовать НЕСКОЛЬКО веток consumer-producer с ОДНИМ всего пулом у каждого producer и хорошим автоматическим load balancing, в то время как в случае кольцевого буфера у нас пул объектов привязан к конкретной ПАРЕ consumer-producer, а не к именно producer (ведь пул нужен именно ему).

·>Нет, RTFM.
·>Вот скажем 2 продьюсера делают балансинг на 2 консьюмера https://github.com/LMAX-Exchange/disruptor/blob/master/src/perftest/java/com/lmax/disruptor/workhandler/TwoToTwoWorkProcessorThroughputTest.java

Ты не понял о каком балансе речь, вестимо.
У нас источником данных является producer. Их несколько. На каком-то из них периодически случается всплеск трафика, соответственно, пул должен вырасти только у этого producer-а. Балансить надо объкты м/у личными пулами, а в дисрапторе такой баланс физически невозможен.

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

Но! Одни и те же данные (принадлежащие одному и тому же набору) будет неэффективно обрабатывать параллельно из разных потоков, бо эти потоки будут встречаться на разделяемых хранилищах этих данных и тормозить еще больше. В общем, такая схема работает тем с большими издержками, чем больше трафик. Поэтому, самой эффективной схемой из всех возможных в случае нескольких потоков является конвейер. Это тоже основы жанра высокоэффективной обработки данных, — любые числодробилки построены именно так и никак иначе. Потому что чем выше трафик, тем более дешевой будет каждая операция на конвейере, ведь в случае наличия данных в межпоточной lock-free очереди обращение к ней фактически бесплатное — ровно в две машинные команды без всяких барьеров памяти и дорогих interlocked-операций.


V>>Кинь мне плиз мою ссылку.

·>https://github.com/LMAX-Exchange/disruptor/blob/master/src/perftest/java/com/lmax/disruptor/queue/ThreeToOneQueueThroughputTest.java

ОК, я посмотрел схему в комментах и увидел знакомый сценарий.
Собсно, это самый популярный сценарий "много-один".


V>>Писали нубы, нихрена не соображающие в устройстве современных систем. ))

·>Голословно.

Законы HFT-жанра специфичны в том, что свои ноу-хау никто не раскрывает, бо это конкурентное преимущество на этом тесном рынке.
Раз они выложили дисраптор в паблик, значит им он больше не нужен. Се ля ви.

По-видимому, они нашли более эффективную модель и я хорошо понимаю — какую именно.
А вы подбираете за ними объедки, судя по всему.
Re[53]: dotnet vs java 2016-2020
Здравствуйте, ·, Вы писали:

V>>Я не хуже тебя представляю, что там с потоками в Джава и как оно устроено. И при чем тут язык или системные библиотеки.

·>А что причём? Твоё личное мнение?

А какое тут вообще может быть мнение? ))
Программист должен уметь различать сущности языка (например "класс") и экземпляры сущностей (конкретный класс Thread).

Я хорошо понимаю причины твоего упорства, т.к. в стандарт языка Джава входит не только описание самого языка, но и минимальной инфраструктуры вокруг него. Однако, не надо путать одно с другим. Если уж говорить о synchronized, то, скорее, надо говорить об обязательном Мониторе в реализации инфраструктуры, чем о Thread, бо Монитор прекрасно работает даже когда мы вызываем джавовский код из потока, созданного не через джавовский класс Thread.


V>>А для борьбы с глупостью стоило посмотреть на язык go, где потоки встроены в сам язык.

·>Каким образом они там "встроены"? Судя по твоим рассужениям так же — часть библиотеки.

Из моих рассуждений следует ровно противоположное. А из твоих рассуждений следует лишь одно — ты много пишешь здесь и мало читаешь вовне. ))
Таки, посмотри на go, там есть на что взглянуть. Собственно, само название языка — это название конструкции по запуску нового вычислительного потока/задачи в этом языке.


V>>·>Ещё намёк — в каком пакете находится класс Thread?

V>>Плевать с большой колокольни.
·>Плюй, не плюй, а факт остаётся фактом.

Факт чего? Имени собственного пакета?


V>>·>А вот всякие сетевые сокеты, файлы, коллекции, регекспы и прочее — да, это часть стандартной библиотеки, а не языка.

V>>Я правильно понимаю, что от одного лишь имени собственного пакета "lang" у тебя малость зрение меняется?
·>А у тебя зрение меняется когда факты противоречат твоим убеждениям.

Так ты мне факты не показал еще.


V>>Треды — это отъемлимая часть аж бегом.

V>>Ты демонстрируешь тут повадки новичков в Джаве, которые на голубом глазу путают язык и VM.
·>Ну погугли что такое monitorenter/monitorexit и описание поведения других инструкций в многопоточном окружении.

Нашел что просить погуглить. Ты бы еще "мама мыла раму" попросил погуглить.

Лучше погугли железные реализации джава-машинки и что там было реализовано в железе, а что нет. И почему именно так.


V>>·>Причём тут вообще сокеты? Зачем ты упомянул их? Как они с протоколами HTTP или FIX связаны?

V>>Напрямую связаны, ес-но.
·>Нет, конечно, не связаны. Или у тебя есть какие-то доказательства?

Конечно есть. Это сетевая модель OSI.
Прямо по этой фразе и гуглить.
Собсно, в описаниях самих протоколов четко прописывается на каких уровнях модели OSI обитают эти протоколы.


V>>·>В смысле у вас только IOCP сокеты в нативе

V>>В смысле виденные мною HTTP-серваки на дотнете используют такие сетевые ср-ва (асинхронный IO), которые были разработаны в нейтиве.
·>Не путай HTTP-сервер и HTTP-протокол.

Не виляй.


·>на джаве обычно есть pure-java реализация стандартными средствами и нативные модули для работы со специфичными под конкретную систему нативными имплементациями, если есть что-то специфичное, конечно.


Бессмысленное бла-бла-бла.


V>>

V>>Стандартный цикл обращения объектов через межпоточный буфер и обратно в "пул" реализованы как две встречных очереди

V>>Тут стоило помедитировать. Это СТАНДАРТНЫЙ подход. Это, блин, сверх-мега-стандартный подход для таких вещей. Это база, уровень 0. ))
·>Где в дизрапторе происходит генерация объектов? Что ты вообще назвал генерацией объектов?

Это ты назвал, я тут причем?


V>>Две встречные очереди образуют "кольцо". Эдакие чётки, как у попа, только вместо пальцев правой и левой руки у нас производитель и потребитель. Один берет из пула объект, подготавливает его и пихает "туда". Другой обрабатывает и пихает "обратно".

·>Что-то какое-то странное представление. Обычная очередь, одна, как в ларёк за пивом. Очереди образуют кольцо?.. Брр. Как-то всё переусложнено.

Ты называешь это сложным?
ОК.


V>>Чем ring-buffer отличается от двух встречных очередей? Да ничем, кроме того, что реализован не на связанном одностороннем списке объектов, а через прибитый к реализации массив фиксированного размера, что считается самой худшей схемой из всех известных. )) Ну, кроме случая, где генерирование и потребление происходит заведомо с одинаковой скоростью,

·>Нет, когда потребление в среднем не медленнее продьюсинга.

Интересует как раз не в среднем.


V>>как при воспроизведении аудио, например. Более того, запись и чтение из кольцевого буфера на один CAS дороже, чем в стандартной схеме межпотокового буфера. Ну и, самое главное, часто мы имеем обращение к одной и той же линейке кеша из разных потоков (ядер) в такой схеме, что до 6 раз (в среднем) тормозит любую межпоточность. Ладно аудио, там десятки-сотня пакетов в секунду от силы, но для HFT это смерть. ))

·>Там в одну линейку _пишут_ только продьюсеры, консьюмеры только читают.

Это ты так расписался в отсутствии представления о "когерентности кеша"? ))

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


·>В приведённом тобой тесте было три продьюсера.


Да хоть десять для lock-free.


·>Тут уже мало что можно сделать иначе. В случае одного продьюсера дизраптор действительно раскочегаривается по полной.


Если ты работаешь в этой области, то должен знать, что во многих биржах идёт минимум 2 UDP-фида для данных и их, таки, положено слушать из РАЗНЫХ потоков в силу особенностей работы UDP. А сами пакету сваливать затем в один поток обработки. "Раскочегаренная" обычная схема на lock-free очередях даёт менее микросекунды средней задержки (чиста для инфы).


·>Собственно это как раз одно из преимуществ дизраптора, что он дружелюбен к железу, учитывает все эти кеши и прочие нумы.



Дисраптор — это роспись в нубстве. Я уже высказывал своё мнение:


V>>>>Это и есть дисраптор. Это его базовый Lego-кубик (один из 3-х, вернее, с идентичным интерфейсом).

V>>·>А доказать?
V>>Я всё доказал, пояснив общее устройство такой схемы (две встречных очереди).
·>Я не понимаю почему ты это называешь двумя очередями. В тесте на который ты привёл — очередь одна. В один конец происходит добавление, с другого конца забирают. Никакого "возвращения" нет.


V>>Я, конечно, могу ошибаться, но мне кажется, что тебя сбивает с толку именно ring buffer. Он в этой схеме вообще не причем, но кажется тебе главной деталью.

·>Конечно главная деталь.

Ну вот ты и спалился.


·>Потому что это не очередь. По ринг-буферу могут ползать сразу несколько потребителей.


Это зависит от реализации. Есть разные реализации межпоточных очередей:
(producer-consumer)
— один-один
— много-много
— один-много
— много-один

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

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


·>И их можно огораживать барьерами — потребители C и D могут отработать только после того, как отработали предыдущие A и B (притом не важно — в каком порядке — A/B или B/A). Вот тут с картиночками: http://martinfowler.com/articles/lmax.html


Да пофиг на подробности реализации. Каждая дополнительная фича в этой схеме — это дополнительные тормоза.
В стандартной "раскочегаренной" схеме где пара потоков пишет, а один читает, каждый поток-producer умудряется сделать до 30-40 млн итераций в секунду, а consumer в два раза больше.
В тесте происходит следующее:
Два потока-производителя вынимают из личного пула объект и ставят в очередь.
Поток-потребитель вынимает объект из очереди и возвращает каждый объект в его личный пул.

И тут чем меньше дополнительных операций, тем лучше, бо счет идёт на считанные единицы машинных команд на операцию.


·>Т.е. этот один единственный паттерн позволяет реализовывать довольно сложное взаимодействие между множествами тредов просто складывая их как кубики.


Паттернов много. Понятно, что "много-много" — самый универсальный, но и самый тормозной, при том, что нужен крайне редко, если включать голову.


V>>По последнему. Без ring buffer можно организовать НЕСКОЛЬКО веток consumer-producer с ОДНИМ всего пулом у каждого producer и хорошим автоматическим load balancing, в то время как в случае кольцевого буфера у нас пул объектов привязан к конкретной ПАРЕ consumer-producer, а не к именно producer (ведь пул нужен именно ему).

·>Нет, RTFM.
·>Вот скажем 2 продьюсера делают балансинг на 2 консьюмера https://github.com/LMAX-Exchange/disruptor/blob/master/src/perftest/java/com/lmax/disruptor/workhandler/TwoToTwoWorkProcessorThroughputTest.java

Ты не понял о каком балансе речь, вестимо.
У нас источником данных является producer. Их несколько. На каком-то из них периодически случается всплеск трафика, соответственно, пул должен вырасти только у этого producer-а. Балансить надо объкты м/у личными пулами, а в дисрапторе такой баланс физически невозможен.

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

Но! Одни и те же данные (принадлежащие одному и тому же набору) будет неэффективно обрабатывать параллельно из разных потоков, бо эти потоки будут встречаться на разделяемых хранилищах этих данных и тормозить еще больше. В общем, такая схема работает тем с большими издержками, чем больше трафик. Поэтому, самой эффективной схемой из всех возможных в случае нескольких потоков является конвейер. Это тоже основы жанра высокоэффективной обработки данных, — любые числодробилки построены именно так и никак иначе. Потому что чем выше трафик, тем более дешевой будет каждая операция на конвейере, ведь в случае наличия данных в межпоточной lock-free очереди обращение к ней фактически бесплатное — ровно в две машинные команды без всяких барьеров памяти и дорогих interlocked-операций.


V>>Кинь мне плиз мою ссылку.

·>https://github.com/LMAX-Exchange/disruptor/blob/master/src/perftest/java/com/lmax/disruptor/queue/ThreeToOneQueueThroughputTest.java

ОК, я посмотрел схему в комментах и увидел знакомый сценарий.
Собсно, это самый популярный сценарий "много-один".


V>>Писали нубы, нихрена не соображающие в устройстве современных систем. ))

·>Голословно.

Законы HFT-жанра специфичны в том, что свои ноу-хау никто не раскрывает, бо это конкурентное преимущество на этом тесном рынке.
Раз они выложили дисраптор в паблик, значит им он больше не нужен. Се ля ви.

По-видимому, они нашли более эффективную модель и я хорошо понимаю — какую именно.
А вы подбираете за ними объедки, судя по всему.