Pull to refresh

Comments 12

Ещё один любопытный вопрос - что из себя будет представлять порождённый процесс: обычный линейный код? А если он тоже захочет работать в event loop?
Порожденный процесс представляет собой полную копию своего родителя. В случае event loop лучше использовать потоки, если конечно модель позволяет :))
perl не позволяет, к сожалению. Я тестирую производительность нитей каждые несколько версий perl, и в последний раз она всё ещё находилась ниже плинтуса.
Так в перле и event loop полноценного нет (если имеется ввиду aio, iocp, kqueue, kevent), разве только poll/select, но это очень медленно.

А использовать имеет смысл, если SMP.

Обработки форк и не должно быть. Процессы нужно форкать _до_.
Event loop - есть. Вполне полноценные. Моя реализация использует epoll, а CPAN-модуль Event::Lib использует libevent (т.е. тот же epoll под линухом, kqueue под *BSD, и другие методы в других системах).

SMP здесь не при чём, Вы, вероятно, не поняли суть вопроса. Запускать какие-то задачи в отдельных процессах смысл есть не зависимо от наличия SMP. Вопрос в том, есть ли смысл запускать их через fork, без exec?

Форкать _до_ далеко не всегда возможно, задачи требующие обработки в отдельном процессе могут возникать в процессе получения каких-то событий, на все случаи жизни тут заранее ненафоркаешься.
Вроде грабли с fork связаны с особенностями epoll в linux - наследованием дескрипторов
Это частный случай. Посмотрите на ситуацию более широко: есть процесс, в котором настроены какие-то таймеры, сигналы, есть даже очередь ещё не обработанных пользовательских событий (ну, типа одна часть кода другой сообщение послала) - это помимо событий I/O. И вот fork этот процесс дублирует, и таких процессов становится два.

Если второй процесс просто будет 20 минут обсчитывать пачку данных, сохранит результат на винт и выйдет - один разговор. В этом случае, действительно, большинство побочных эффектов будет связано с особенностями реализации epoll и FD. Но что если второму процессу нужно делать что-то более сложное, и он тоже хочет использовать event loop? А у него в памяти осталась куча настроенных событий от родительского процесса...

Вообще, идея сдублировать процесс в котором настроена куча событий и продолжить выполнять оба таких процесса одновременно воспринимается достаточно дико.
Да, у меня была ситуация - форкнуть и запустить другой скрипт, использующий свой event loop. В результате получилась ж...
Если честно, не очень понял суть проблемы. Как то сумбурно все понял. То ли примеров не хватает из жизни, то ли тормоз.

А как в вашем понимании эта проблема должна быть решена? Как эта же технология евент-лупов реализована в других языках/системах?
А вот так и реализована — без обращения внимания на проблему fork. В частности, под виндой, насколько я слышал, fork нет вообще; а нет fork - нет проблемы.

Похоже, эту проблему автоматически решить нельзя. Только ручками: в каждом приложении используещем event loop внимательно следить за всеми fork-ами (в т.ч. и находящимся внутри используемых этим приложением чужих библиотек!), думать какие проблемы эти fork-и вызовут и как их обойти. Посколько гимор всё это просто дикий, то рекомендуется одновременно event loop и fork не использовать. Либо на-fork-ать нужные процессы до входа в event loop, либо вместо fork использовать fork+exec (и закрывать все fd) создавая новый процесс никак не могущий нарушить работу event loop в основном процессе.
В другом вашем посте вы упоминули, что библиотека libev решает или по крайней мере пытается решать эту проблему функциями ev_default_fork, ev_loop_fork. Насколько я понял из документации, эти функции выполняют переинициализацию используемого объекта (например epoll) на уровне ядра, после чего потомок может использовать функции библиотеки. Вот только что скрывается за этой "переинициализацией"?
Помимо epoll хватает и других событий — таймеры, пользовательские, сигналы, etc. Всё это добро автоматически переинициализировать невозможно — ведь если делается fork без exec в процессе работы event loop, то предполагается что оба процесса продолжат работать в event loop... так что просто автоматически при fork почистить все обработчики событий в child как-то не правильно и не логично.

Насколько я понял, libev решает эту проблему не какой-то магической переинициализацией epoll_fd, а предоставляя возможность пользователю установить свой обработчик fork — который будет вызван при fork и позволит юзеру самому разрулить, какие обработчики событий оставить в child, а какие в parent. Это достаточно сложная задача, т.к. зачастую для этого нужно знать текущее состояние приложения, а оно в event-loop based приложениях зависит от слишком многих факторов. Впрочем, понятно, что в разных процессах должен быть разный epoll_fd, так что libev действительно может создавать новый epoll_fd автоматически в child процессе — но это не сильно облегчает жизнь программисту и основная сложность всё равно ложится на его обработчик события "fork".
Sign up to leave a comment.

Articles