LINUX.ORG.RU

История изменений

Исправление Siborgium, (текущая версия) :

  • запускаю 1000-3000 бинарников - всё ок
  • на 7000 бинарников - картина на скрине

Не надо так. По этому поводу уже все расписали. Даже 1000 одновременно исполняющихся (не спящих, не ждущих, а активно исполняющихся) процессов будут давать большой contemption. Тот же мейк неспроста с JOBS=$(nprocs) запускают.

Далее, если все это вместе логически связано и нет требований к безопасности, то лучше процессов делать меньше – а тредов больше. Они легче, и управлять ими проще.

Больше процессов не значит больше обрабатываемых данных. Даже если обработка данных логически параллелится (что вовсе не факт), поднимать параллелизм выше аппаратного уровня будет только ухудшать производительность.


Теперь касательно обработчика.

std::unique_lock<std::mutex> lock(this->mutex);

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

if (auto event = internal_events_.pop(); event) {

if (auto event = my_events_.pop(); event) {

if (auto event = my_q_events_.pop(); event) {

Не надо так делать. Ты замыкаешь три мьютекса по очереди просто чтобы проверить наличие элемента в каждой очереди. Замкнуть один и проверить все три было бы значительно дешевле. Если бы только был какой-то способ знать, когда придет ивент, и сразу его обработать…

Код простой, в простое опрашивает ивенты

Не нужно их опрашивать. Нужно, чтобы приходящий ивент будил твой обработчик, обработчик его обрабатывал и засыпал обратно. epoll, poll, select, что угодно. Если ивенты генерируются внутри процесса, то condition_variable.

Далее, если событий много, не требуется мгновенная обработка ивента, а только порядок, то оптимальнее будет наполнить буфер ивентов и отдать его на обработку, обработать их разом и уснуть опять.

Чем меньше свичей контекста (т.е. чем меньше тредов/процессов на единицу параллелизма), чем меньше точек синхронизации (мьютексы, condition_variable, даже атомики в seq_cst), тем больше полезной работы будет выполнять твой код.


Кстати, если потоки много спят, есть смысл сократить их число и пытаться переходить на корутины. У Яндекса, вроде как, взлетело.

Исправление Siborgium, :

  • запускаю 1000-3000 бинарников - всё ок
  • на 7000 бинарников - картина на скрине

Не надо так. По этому поводу уже все расписали. Даже 1000 одновременно исполняющихся (не спящих, не ждущих, а активно исполняющихся) процессов будут давать большой contemption. Тот же мейк неспроста с JOBS=$(nprocs) запускают.

Далее, если все это вместе логически связано и нет требований к безопасности, то лучше процессов делать меньше – а тредов больше. Они легче, и управлять ими проще.

Больше процессов не значит больше обрабатываемых данных. Даже если обработка данных логически параллелится (что вовсе не факт), поднимать параллелизм выше аппаратного уровня будет только ухудшать производительность.


Теперь касательно обработчика.

std::unique_lock<std::mutex> lock(this->mutex);

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

if (auto event = internal_events_.pop(); event) {

if (auto event = my_events_.pop(); event) {

if (auto event = my_q_events_.pop(); event) {

Не надо так делать. Ты замыкаешь три мьютекса по очереди просто чтобы проверить наличие элемента в каждой очереди. Замкнуть один и проверить все три было бы значительно дешевле. Если бы только был какой-то способ знать, когда придет ивент, и сразу его обработать…

Код простой, в простое опрашивает ивенты

Не нужно их опрашивать. Нужно, чтобы приходящий ивент будил твой обработчик, обработчик его обрабатывал и засыпал обратно. epoll, poll, select, что угодно. Если ивенты генерируются внутри процесса, то condition_variable.

Далее, если событий много, не требуется мгновенная обработка ивента, а только порядок, то оптимальнее будет наполнить буфер ивентов и отдать его на обработку, обработать их разом и уснуть опять.

Чем меньше свичей контекста (т.е. чем меньше тредов/процессов на единицу параллелизма), чем меньше точек синхронизации (мьютексы, condition_variable, даже атомики в seq_cst), тем больше полезной работы будет выполнять твой код.

Исходная версия Siborgium, :

  • запускаю 1000-3000 бинарников - всё ок
  • на 7000 бинарников - картина на скрине

Не надо так. По этому поводу уже все расписали. Даже 1000 одновременно исполняющихся (не спящих, не ждущих, а активно исполняющихся) процессов будут давать большой contemption. Тот же мейк неспроста с JOBS=$(nprocs) запускают.

Далее, если все это вместе логически связано и нет требований к безопасности, то лучше процессов делать меньше – а тредов больше. Они легче, и управлять ими проще.

Больше процессов не значит больше обрабатываемых данных. Даже если обработка данных логически параллелится (что вовсе не факт), поднимать параллелизм выше аппаратного уровня будет только ухудшать производительность.


Теперь касательно обработчика.

std::unique_lock<std::mutex> lock(this->mutex);

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

if (auto event = internal_events_.pop(); event) {

if (auto event = my_events_.pop(); event) {

if (auto event = my_q_events_.pop(); event) {

Не надо так делать. Ты замыкаешь три мьютекса по очереди просто чтобы проверить наличие элемента в каждой очереди. Замкнуть один и проверить все три было бы значительно дешевле. Если бы только был какой-то способ знать, когда придет ивент, и сразу его обработать…

Код простой, в простое опрашивает ивенты

Не нужно их опрашивать. Нужно, чтобы приходящий ивент будил твой обработчик, обработчик его обрабатывал и засыпал обратно. epoll, poll, select, что угодно. Если ивенты генерируются внутри процесса, то condition_variable.

Далее, если не требуется мгновенная обработка ивента, а только порядок, то оптимальнее будет наполнить буфер ивентов и отдать его на обработку, обработать их разом и уснуть опять.