Pull to refresh

Comments 62

В целом статья хороша, плюсанул. Но замечание у меня все же есть.
ИМХО, не стоит расшаривать между несколькими процессами одно и то же соединение с БД, если вы не знаете, как именно клиентское API данной БД ведет себя в таких случаях. Можно нарваться на рассинхронизированную ситуацию, когда запросы к БД и ответы перемешаются в сокетах.
Вообще гуайды рекомендуют непосредственно перед fork() закрывать все дескрипторы, кроме тех с которыми вы «точно знаете, что делаете», типа слушающих сокетов.
В большинстве случаев будет правильным устанавливать в каждом клиенте свое соединение с БД после fork(). Тогда и закрытие коннекта в каждом клиенте не вызовет описанных в посте проблем.
А что по поводу обработки изображений? Вообще как можно ускорить обработку изображений? Кроме как на пользовательской стороне используя flash…
по числу ядер можно распараллелить обработку нескольких изображений…
В заголовке обещаете многопоточную программу, в статье пишите про процессы.
2 процесса = 2 потока. Параллелизм уровнем выше :)
2 процесса = 2 процесса. Вы принципиальную разницу между потоками и процессами представляете?
Я даже представляю как сделать параллелизм внутри приложения на файберах (возможно раскрою вам секрет, но были операционки без «потоков» (вообще говорят нитей)).
Вы не верите мне что в 2х процессах в сумме будет МИНИМУМ 2 нити? :)
Конечно я вам не верю, с чего бы верить. Вы упорно показываете мне, что разницы не понимаете.
Я вам ничего не показываю. Выводы из сказанного мною вы вольны делать сами.
Основная мыль неизменна.

2 процесса = минимум 2 нити. Как следствие параллелизм уже будет. Но уровнем выше. Если цель — достичь параллелизм в программе — это достижимо через форк.

Это не многопоточность в её классическом понимании (потому что как сказал Sega100500 новые нити будут в другом адресном пространстве), но тем не менее параллельное исполнение того же кода происходит.
Да, это параллельность, но все же это не потоки, а параллельные процессы, хотя бы с этим согласитесь.
Сказать, что «2 процесса = минимум 2 нити» это как сказать «программируя на Си, я программирую на ассемблере» — а чего, всё равно же в результате будут те же самые машинные коды.
Это не многопоточность в её классическом понимании… но тем не менее параллельное исполнение того же кода происходит.
Это вообще не многопоточность, в любом понимании. И, конечно, параллельное выполнение происходит, потому что многопоточность — не единственный способ выполнить что-то параллельно.
Ассемблер — это язык. И программируя на C, вы не программируете на ассемблере. Компилятор С компилирует в бинарник, в машинные инструкции. Пользуясь вашим подходом скажу что вы не понимаете разницу между языком ассемблер и машинными инструкциями :)
Вы точно прочитали то, что я вам написал, нет? Прочтите первое предложение от начала и до конца и обратите внимание на слова «это как сказать».
Но дело в том, что система создавая процесс порождает в нем главный поток.
В 2х процессах будут минимум 2 потока.

Вы говорили, что не согласны с этим утверждением. Уточните с чем именно.
Я в первом же комментарии написал с чем несогласен. В статье — не многопоточная программа.
Не надоело еще в каждой статье про распараллеливание в PHP доказывать что это нельзя называть многопоточностью? Многопроцессность звучит уж слишком коряво. Никто не подразумевает реальную многопоточность. Только эмуляцию.
Используя форки в php обычно пытаются эмулировать именно многопоточность, поэтому такое название. Если вы вообще программируете на PHP, то в его контексте этот термин должен быть вполне понятен.
Я против бардака.

Во-первых, если многопроцессность плохо звучит, никто не мешает выдумать новый термин. Например, можно писать «эмуляция многопоточности».

Во-вторых, в ПХП многопоточность может появиться, что тогда делать с горой мусора.

В-третьих, в программировании термины важны, чтобы понимать о чём вообще речь, а не расписывать абзацем что вы имели ввиду.
Предложите свое название статьи, я поправлю. Заметьте, что в тексте я термин «многопоточность» не использовал :), название в заголовке я использовал для краткости.
«Написание многозадачных программ на PHP»
Поменял название. Надеюсь, так лучше и больше не вызывает у «понимающих людей» такого страшного баттхёрта :).
А что, давайте называть компиляцию интерпретацией, процедурное программирование — функциональным, а машину, выполняющую байт-код — микропроцессором?
Паралелизм в программах на PHP.

По феншую это не потоки же всетаки )
Процедурное программирование функциональным уже многие называют :( Наверное потому что в Си нет отдельного понятия процедуры, а просто void функция. Прикольно бывает слышать из уст «крутого» java-кодера: «php отстой, все быдлокодеры пишут на нём в функционально, а не ооп».
Я скажу честно: я не знаю, как называется такой стиль программирования, когда использует только fork() + примитивы IPC, но не разделяемая память. Термин «многопоточность» здесь не очень подходит, но остальные — ещё хуже, ибо они не отражают возможностей и особенностей fork().
С этим утверждением я не спорил. Я вам написал что 2 процесса = 2 потока.
Этакая «квазимногопоточность». Ещё раз. Я согласен что в статье нет «многопоточности».

Кроме того что вы не заметили смайлик в моём сообщении, вы ещё и зачем то зацепили меня намекая на отсутствие у меня знаний в области параллелизма.

НЕ нужно так остро реагировать :)
А я вам написал, что ваше утверждение равнозначно утверждению, что «программируя на Си, я программирую на ассемблере». Вы ещё скажите, что если рядом поставить две машины, где выполняются по одному процессу, то получится многопоточная среда. Разницы между этим и вашем утверждением я не вижу.

Термин «многопоточность» говорит о множестве потоков в одном процессе. Так что 2 процесса ≠ 2 потока. 2 процесса = 2 процесса.
Вы не прочитали сообщение на которое ответили :)
UFO just landed and posted this here
Если мне память не изменяет, то многопоточность предполагает использование единого адресного пространства одного процесса. В данном же случае, если необходимо взаимодействие между такими «потоками», потребуется организовывать межпроцессное взаимодействие.
Удобное межпроцессное взаимодействие организовать в принципе не трудно. Чуть выше написал ссылку на статью, где организовано полноценное взаимодействие процессов с использованием fork и libevent.
Реализована передача данных в обе стороны, включая события. Это позволяет еще и использовать один процесс многократно не тратя ресурсов на новый форк.
Дело ведь не только в межпроцессном взаимодействии, а еще и в синхронизации общих данных между такими вот параллельными «потоками». Например, обрабатывая один массив параллельно, сделать так, чтобы он выглядел всегда одинаково для каждого из таких «потоков».
2012 год, вы пишете на хабре как использовать fork в php
фуфу?
Согласен. Но около 200 добавлений в избранное свидетельствуют о том, что еще не все на хабре разбираются в том, как работает этот системный вызов. Более того, я ни разу не утверждаю, что я сам знаю о всех тонкостях работы с ним, и сам с радостью бы почитал такого рода статейки, если бы они были.
Новичков всегда хватает. Только все эти статьи написаны же уже.
И да и нет. К сожалению, всё, что я видел, касалось демонов на PHP, или долго исполняющихся программ. Моя заметка касается программ, которые исполняются несколько секунд и работают в интерактивном режиме с точки зрения пользователя.
Вы вводите новичков в заблуждение, а опытных раздражаете термином многопоточность.
Убрал термин «многопоточность» из заголовка, чтобы не смущать «опытных».
Статья не плохая, но тут много лишних «наворотов»… а каждый такой «наворот» может привести к потенциальной ошибки.
Первое, что хотелось отметить: РНР — это не тот язык, где должна использоваться параллельная обработка. надо просто принять это, а не правой рукой чесать левое ухо.
Второе и главное замечание: если хотите делать форк, то делайте его до открытия всяких файлов, сокетов и соединений с БД (хотя это практически одно и тоже)
Как упоминалось в статье — pcntl_fork() — это всего лишь враппер на системным выводом fork
для справки читаем man fork и у вас сразу предотвратится куча багов
Статья ценная, решает много вопросов, связанных с адекватной скоростью работы скриптов больших PHP-сайтов. Единственный вопрос: как вы решаете/предлагаете решать вопрос передачи данных между форками? Хотя бы на уровне возвращения значений из дочерних форков.
Конечно, зачем нам нативные пайпы, давайте лучше поставим еще один сервак с редисом.
семафоры не решают всей проблемы
Самый простой способ — через временные файлы и файловые же блокировки… Есть более продвинутые способы межпроцессного взаимодействия, но суть не отличается: весь обмен данными только в сериализованном виде.
обмен через shmem — более продвинуто :)
А как оно будет работать из mod_php например? Форкать весь апач?
Впрочем, люди пишут, что используют. Но нужно понимать, что форкать апач — это очень плохая идея. То же самое касается PHP-FastCGI / PHP-FPM. То есть, нужно очень хорошо понимать, что вы делаете, и зачем. Тот же system() на самом деле форкается, но он это делает очень аккуратно, причём он делает именно fork()-exec(), а не просто fork(). Лучше не думайте о том, чтобы использовать fork() на стороне mod_php или FPM.
Такие штуки нужны для скриптов, а там ни о каком mod_php речи не идёт. В обычной выдаче такие вещи лучше решать другими путями — например, через fastcgi_finish_request()
>А как оно будет работать из mod_php например? Форкать весь апач?
НИ КАК
читаем внимательно ман…
pcntl_fork() не работает в mod_php
Делать нечего, только читать маны по языкам на которых я не пишу.
это не ман по языку, а ман по системным вызовам, которые ты, как программист, должен знать, вне зависимости от языка, на котором идет разработка.
Казалось бы, при чем здесь «вне зависимости от языка» и «mod_php».
Я уже упоминал, что PHP не предназначен для параллельной обработки данных, в том виде, ка мы ее понимаем :)

Единственное и правильное применение fork() в PHP — это ввод процесса в бэдграунд или демонизация процесса.

Вся параллельная обработка данных решается на уровне архитектуры между процессами.
Хотим организовать параллельную обработку каких-то данных — запускаем (форкаем один раз) сколько надо процессов, обмен с которыми идет либо по shmop, либо по сокетам или shmem.
мастер процесс может посылать сигналы (USR1, USR2 ) на начало обработки и принимать ответные сигналы (правда он не будет знать, от какого процесса пришел этот сигнал)
можно/нужно использовать симофоры для синхронизации окончания обработки данных процесом.

При работе с сигналами я использую libevent, можно так же ее использовать для приема данных по сокетам.

Архитектура приблизительно должна быть следующей: WEB скрипт через сокеты или shm закладывает некоторые данные, посылает сигнал мастер процессу и заканчивается.
Мастер процесс тиражирует этот сигнал по дочерним процессам, задача начинает решаться…

WEB скрипт по AJAX через некоторые промежутки тягает WEB скрипт, который просматривает статус задачи (В ПРОЦЕССЕ), который находится в определенном блоке shm

Как только все процессы завершат исполнение задачи и перейдут в режим ожидания новой, мастер процесс получит уведомление, сформирует окончательные данные и обновит блок статуса задачи на ВЫПОЛНЕНО.

WEB скрипт по AJAX через WEB скрипт, просмотрит статус задачи (ВЫПОЛНЕНО) и вызовит скрипт показа результатов.

как-то так…
И никаких форков во время выполнения WEB скриптов!!!
а пока Пользователь ждет расчета своей мега-задачи ему пожно показывать
красивый прогрессбар или крутить песочные часики…
Ну, да, всё правильно, кроме того, что эти скрипты могут исполняться не на той же машине, поэтому синхронизацию лучше делать не через shm, а, например, через базу данных.
ну тогда уж через сокеты. по этому я использую libevent и для сигналов и для обмена данными с фронт-скриптами. А для воркеров я бы предпочел обмен через shm.
База — это слишком тяжело, и лишнее звено. Базу надо использовать для хранения данных, а не для обмена.
несомненно, лучше все тяжелые вычисления запускать на другой машине, если она конечно есть.
Sign up to leave a comment.

Articles