Re: 10K problem for keep-alive utility
От: watchmaker  
Дата: 09.11.23 00:06
Оценка: 1 (1)
Здравствуйте, avovana, Вы писали:

A> 1ая реализация

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


A> А в это время уже события на fd новые могут придти.

Ну и что?
Они не потеряются. А если запись в output тормозит, то всё равно не сможешь в output вывести об этом сообщение, даже если сумеешь обработать событие на fd раньше.

Уметь обрабатывать события раньше имеет смысл только если почему-то нужно узнавать более точное время, когда оно наступило. Или если нужно уметь дедуплицировать события: например, если произошёл переход up->down->up, но в output ещё не успели записать строку про up->down, то не записывать в output ничего вообще — как будто соединение и не падало.

A> синхронно записывая в консоль, файл.

Можешь писать асинхронно :)
Добавить файл в epoll и точно так же слушать на нём события.
Можно и одним потоком обойтись, но ниже будет вариант с парой, который может быть проще для восприятия и реализации — потому что стандартные примитивы очередей и future/promise проще, чем автомат поверх событий epoll.



A> проходимся в цикле по выданному пулу fd синхронно записывая в консоль, файл

Скорее имеет смысл подготовить данные про группу дескрипторов и один раз записать в файл, а не на каждый дескриптор дёргать вывод в файл. То есть либо использовать, условно говоря, один writev вместо многих write, либо использовать обычную буферизацию записи (просто при выводе в консоль она может быть всего лишь построчной по умолчанию).

A> Подумал над memory mapped file + спин лок. Спин локом защищаем общую переменную — смещение. Поток подготовил строку для вставки в файл. Теперь ему нужно узнать по какому смещению её записать.

A> Он лочит спин лок, сохраняет себе смещение, обновляет его — прибавляет к нему длину строки, которую сейчас вставит. Отпускает спин лок. Вставляет по полученному смещению строку.
A> Т.е. критическая секция получилась маленькая.

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

К тому же с таким подходом не всё так просто: нужно будет ведь ещё как-то уведомлять читателя о том, откуда из файла уже можно читать данные. Читатель тогда тоже должен какой-то счётчик со смещением чтения иметь, который не совпадает со смещением для записи. И который не тривиально обновлять, так как записи блоков будет завершаться не в монотонном порядке — и счётчик обязан будет уметь как задерживаться, если за ним идёт дыра, так и прыгать на несколько записей вперёд, когда в дыру закончится запись.

Можно посмотреть как это делается правильно в lock-free-like очередях поверх циклических буферов. Но это не совсем просто и, главное, слишком избыточно.


A>Получаем от epoll список fd. Делим его на 4 — получаем 4 списка. Каждый отдаём на обработку в пул потоков.

A>Минус в том, что сгородили целый пулл потоков ради всего-лишь вывода в файл. И файл-то один. Нужно же синхронизировать к нему доступ. Через мьютекс? Вся многопоточность убьётся об него.

Идея почти нормальная. Только откуда-то из непонятного места возникает синхронизация к файлу.

Заводи два типа потоков:
Собственно, это почти всё.
Каких-то сложных потоков данных или блокировок нет — всё собирается из стандартных примитивов.
В фантастическом случае, если например промежуточная очередь тормозит, то понятно как её можно заменить (уверен, что кто-нибудь посоветует тут поиграть со всякими lock-free очередями).

И легко сделать дедупликацию событий, чтобы промежуточная очередь не росла бесконечно и чтобы программа не упала по превышению памяти, если вдруг запись в output застопорится. Так как обрабатывающий поток будет видеть, что его же блок событий с предыдущей итерации ещё не был передан для записи, и может легко сделать агрегацию (опять же, можно это делать не блокируя соседние потоки, если они есть).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.