почему бы и нет, если нужно обработать большое количество данных, и есть возможнсть разбить на части… это конечно не потоки, но позволяет разбить действие на чати, скорость увеличится
Ну вот начинается… Я не плохо могу написать тоже самое на java или даже на C++ но выигрыш в скорости будет незначительный по сравнению со временем которое я потрачу на разработку и внедрение.
class SomeClass extends Thread {
public void run() {
// Some usefull work
}
}
Насколько больше времени вы потратите, написав это на Java, а не на похапе? По сути, четыре строчки на джаве против примерно тридцати на похапе. Конечно, когда ресурсы ограничены такой вариант очень даже подходит. Сам юзаю нечто подобное (только без ООП и прочих «канделябров») на шаред-хостинге. Но если вдруг состоится переезд хотя бы на VPS этот шлак обязательно заменю на джава-реализацию. Ибо велосипеды с квадратными колёсами сейчас уже мне не нравятся :)
Простите уважаемый автор, но то о чём вы пишите это не почти многопоточность, а то на что ссылаетесь довольно далёкое имеет отношение к неблокирующим сокетам. У вас речь идёт о небольшом классе для запуска кучи процессов CLI PHP, что уже само по себе является костылём против PCNTL, коих на Хабре не развиваемых и не поддерживаемых уже с десяток было.
Если последующая обработка не требует параллельности — то мульти-cURL вполне подойдёт. Иначе делаете аналогично автору поста — запускайте X «потоков» каждый из которых будет запрашивать и обрабатывать по одному урлу
Как правило это параллельное выполнение некоторого кол-ва медленных, но не слишком ресурсоёмких задач — сетевые конекты к долгоотвечающим сервисам например
Прошу прощения, дал ответ ниже по дереву комментов. Тут главное не путать ресурсоёмкие и долго выполняющиеся. Такая простая параллельная загрузка годиться для простых, в силу каких-либо обстоятельств медленных действий, которые неудобно или невозможно параллелизировать встроенными методами PHP. В примере предлагалось запускать параллельно несколько инстансов PHP в для обхода медлительности функции mail, неисправимой медлительности могут быть особенно подвержены функции системных вызовов, комплдексные функции прочтения файлов и работы с сетью, любые сторонние библиотеки, в коде которых копаться с целью ускорения нет возможности.
Скачать и распарсить 50 (каждый раз разных) html-файлов, используя DOMXpath :) Делать это раз в 10 минут :) Есть шанс, что однопоточное приложение не справится за отведённый промежуток времени (10 минут), поэтому распараллеливаем выполнение — тогда общее время выполнения уменьшается до времени выполнения самого медленного потока + небольшой оверхед. Если не распараллеливать общее время выполнения будет примерно равно сумме времён выполнения задач.
>Если не распараллеливать общее время выполнения будет примерно равно сумме времён выполнения задач.
У вас всё упирается в вычислительные мощности? Concurrency недостаточно и нужен parallelism? Что там у вас за html'ки которые обрабатываются по 12 секунд. Да и если уж всё упирается в вычислительные мощности, то было бы логичнее запускать треды по кол-ву логических процессоров и передавать через тот же пайп хтмльки на обработку.
для выполнения ping для большого количества оборудования, например. Можно прикрутить дополнительный perl скрипт, но удобнее все-же полностью на php писать.
Классический пример потоков(правда десктопный), это GUI и обработка в разных потоках. Если они будут в одном потоке, то во время обработки GUI будет подвисать.
Применительно к вебу — тоже самое, есть сервер, одна из функций, например, массовая рассылка почты. Появилась ситуация когда нужно разослать письма — создаем поток и рассылаем(или, если писем много, создаем n потоков). Так же очень удобно использовать потоки в грабберах. Граббинг в n потоков почти в n раз быстрее:)(до определенного момента). Хотя, в случае граббинга можно использовать curl-multi, но это если граббинг без процессинга.
У меня например на сервере в паралельном потоке весит джаббер бот, который меня извещает об ошибках, и имеет простенькую обработку комманд для получения статистики.
Конечно никто не спорит, что тоже самое можно сделать форками, либо вобще несколькими независимыми приложениями сообщающимися посредством, например, сокетов. Но используя потоки, все вразы проще:)
Конечно за простоту приходится платить проблемами с синхронизацией, но, при аккуратном использование таких проблем не возникает:)
Ну по теме — потоки на форках, это конечно очень уныло. Кстати, была на хабре похожая тема(да почти идентичная, тоже пхпшные потоки на форках), я специально не поленился и погуглил насчет php pthread. И такой проект есть, насчет его статуса не скажу, но если оно работает, это куда лучше форков:)
Если ожидание имеем в следствие какого-то сложного расчёта, то выигрыша и на многоядерном будет немного. А если задержка связана с сетью, вызовом системным или элементарным ожиданием, то и прирост будет огромным. Идеальный вариант это надо 1000 раз запустить скрипт вида «wait 10; echo random()», когда вопрос стоит «ждать или не ждать» и второстепенно «не жирно ли запустить параллельно 10-50-100-1000 процессов php»
Основная фишка тут в том, что пока один поток ждет чего-то, второй в это время выполняется. Т.е., как TDz выше написал, например работа с сетью. Один поток отправил запрос и ждет ответа, второму ответ уже пришел, и он обрабатывает результат, третий за это время успел уже два запроса обработать. В итоге, без потоков эти пять запросов обрабатывались бы последовательно, а с потоками — паралельно.
Ресурсоёмкие задачи параллельно выполнять чревато упиранием в потолок по CPU/IO/OOM. А такой способ выполнения одновременно нескольки медленных задач и экономит нам задержку и утилизирует рессурсы, выполняя ту же задачу быстрее за счёт симультанных запросов, теряем небольшое кол-во памяти на дополнительные инстанции PHP правда. Для простых сетевых операций есть асинхронные сокеты (работать через которые не со всеми протоколами надо сказать удобно/возможно), для системных вызовов есть отправка в бекграунд, а для чего-то другого родного «параллелизатора» в рамках PHP нету — вот и пользуемся многозадачностью (прошу прощения термин тоже не вполне корректный), ведь задачи появляются там где не ждёшь — из последнего на моей памяти надо было получать ответ медленного CLI приложения по SSH с удалённого сервера — время коннекта плюс запуска до выдачи данных более 10 секунд, а нужно дёрнуть скажем сто раз — никакой выгоды от выдумывания варианта как сделать это всё параллельно в рамках одного запущенного PHP нету, если делать цикл будем ждать до новых веников, вот и запускается несколько процессов каждый одним потоком. Ещё думается в случае с сетевой файловой системой могут возникать лаги, которые сокетами не обойдёшь. Нельзя сказать чтоб задач было так уж много, но иногда встречаются ситуации когда запустить несколько рабочих процессов проще и быстрее чем придумывать хитросплетения многих потоков в одном процессе, пусть и в ущерб высоким принципам
— симультанные запросы
— невозможность работать с протоколами, используя асинхронные сокеты
— отправка в бекграунд системных вызовов
я вас не понимаю, честно :) Я старался изучать программирования всеми силами, даже Кнута читал, а не листал. но нет, всё равно встречаются программисты которых я не понимаю…
Прошу прощения если выразился неудачно, я Кнута к своему стыду даже не листал, будем думать в этом корень проблемы :)
1) симультанные говоря проще есть паралельные для которых начало (более менее) одновременно, от англ. simultaneous
2) медленные сетевые коннекты вы предложили параллелить используя асинхронные сокеты, и это делать в любом случае надо. Но не всегда можно распараллелить большое кол-во запросов запросов этим методом — ведь часто для работы со сложными сетевыми протоколами нам дают в руки инструменты высокого уровневя абстракции, тоесть некую блекбоксовую функцию ConnectToSomeCrazyProtocol() которая как на зло ни разу не асинхронная, и не остаётся никакой возможности использовать неблокирующие сокеты так как этого бы хотелось в рамках одного инстанса PHP.
Для этого пришлось бы лезть внутрь существующего кода и чего-то там пилить. По крайней мере мой опыт подсказывает что если экшн достаточно сложен его зачастую проще распаралелить на уровне вызова новых процессов PHP чем переписывая тонкости логики. А если протокол проприетарен, либо есть необходимость использовать конкретный существующий код не предусматривающий модификаций по лицензии, либо код элементарно закрыт каким-нибудь зендовским шифровщиком, тогда самый быстрый а зачастую и один из лучших выходов будет распаралелить процессы PHP
3) я говорил о вызове исполняемых файлов которые потенциально могут быть очень медлительными, system, exec и компания. Неоднократно видел в коде как решают необходимость запустить из скрипта паралельно 10 софтин — в цикле делают system("/home/user/some_soft &") получая таким образом мгновенный возврат — цель конечно достигнута, но я лично считаю это очень неудачным стилем решения вопроса, и привёл как пример воркераунда, в данном конкретном случае типичного кривого хромого quick&dirty
1) pcntl_fork
2) запуск интерпретатора (как в примере выше)
3) вызов через неблокирующие сокеты
4) вызов через мультизагрузку сURL
5) использовать треды (http://code.google.com/p/php-pthreads/).
Для PHP есть модуль, реализующий «честные» треды, поищите, на Хабре о нём упоминали. Ну и конечно, более чем странно упоминать запуск нескольких интерпретаторов как какое-то открытие или даже способ, настолько это простая вещь.
Кстати, PCNTL (точнее — pcntl_fork), который вам часто склоняли в комментариях будет доступен только из командной строки, но скорость работы у него побольше, конечно.
Так что, если вы хотели создать универсальное решение, может сделать поддержку запуска приложения, pcntl_fork, вызова себя же на неблокирующих сокетов или мультизапросами с cURL, а так же тредов через модуль? Причём свести всё вместе так, чтобы было удобно пользоваться?
Мне кажется, в этом случае, народ бы точно сказал вам спасибо.
Я тут не увидел threads. Даже намека на них.
Просто оболочка над streams тут.
Естественно никаких сущностей в примере нет, поэтому «почти настоящая многопоточность» в названии топика звучит очень уж лживо. До нее как раком до китая.
Кстати, когда требуется многопоточность ИМХО намного лучше запускать тем же способом php скрипт вне вебсервера и делать там родной нормальный форк pcntl_fork() :)
pthread для PHP пока не сделали, а жаль :)
Я вот думаю, написать что-ли статью о том, что такое сабж, почему так нельзя делать и почему вообще впринципе нельзя реализовать потоки, даже модулем. И давать каждый месяц при появлении подобных статей.
Как-то странно, все запущенные «процессы» отрабатывали не больше пяти секунд, а результирующее время — 5.58. Пол секунды «накладных» расходов для обеспечения работы десяти «процессов» ИМХО слишком много. Или я что-то недопонимаю?
Почти настоящая многопоточность средствами php 5