Android & Web developer
0,0
рейтинг
13 декабря 2011 в 21:41

Разработка → AzaThread — многопоточность для PHP с блэкджеком

PHP*
В сети гуляет довольно много решений для эмуляции многопоточности в php. Чаще всего они основываются на форках, но есть и вариации на тему с использованием curl, proc_open и т.п.

Все встреченные варианты по тем или иным причинам меня не устроили и пришлось написать свое решение.
Набор требований у меня был следующий:
  • Использование форков;
  • Синхронный режим с сохранением интерфейса при отсутствии необходимых расширений;
  • Многократное использование дочерних процессов;
  • Полноценный обмен данными между процессами. Т.е. запуск с аргументами и получение результата по завершении;
  • Возможность обмена событиями между дочерним процессом-«потоком» и основным процессом во время работы;
  • Работа с пулом потоков с сохранением многократного использования, передачи аргументов и получения результатов;
  • Обработка ошибок выполнения;
  • Таймауты на выполнение работы, ожидание работы потоком, инициализацию;
  • Максимум производительности;

В результате получилась библиотека AzaThread (старое название — CThread).

Для нетерпеливых сразу ссылка на исходники:
github.com/Anizoptera/AzaThread

Описание


AzaThread предоставляет простой интерфейс для создания классов-потоков. Которые на самом деле используют отдельные процессы для асинхронной работы, но вас это не должно волновать. Вы можете посылать события из потока, возвращать результаты, использовать один поток множество раз передавая ему аргументы запуска или создать пул из 16 потоков разгребающих ваши задачи как горячие пирожки не обращая никакого внимания на то, что работа происходит в разных процессах.

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

Для полноценной работы требуются следующие расширения: libevent, posix и pcntl.

Библиотека использует LibEvent и парные сокеты для общения между процессами. Поддерживает 5 вариантов передачи данных (аргументов, результатов и данных событий)!

Варианты привожу сразу с данными производительности. Тестировалось с пулом из восьми потоков на Intel Core i7 2600K 3.40 Ghz (Ubuntu 11.04 на виртуалке VMware). Приведены средние результаты за 10 повторов теста в jps (jobs per second — кол-во задач просто получающих аргументы и отдающих данные в секунду).
jps Описание
1 6501 Передача данных в сериализованном виде через те же сокеты. Вариант по умолчанию.
2 6625 То же самое, но с igbinary сериализацией (наиболее производительный вариант). Используется по умолчанию если igbinary установлен.
3 6194 System V Memory queue (sysvmsg)
4 6008 System V Shared memory (sysvshm)
5 6052 Shared memory (shmop)

Автоматически выбирается расширение для работы с сокетами. Если доступно, то используется расширение sockets, что дает улучшение производительности. В ином случае задействуется stream.

В дочернем процессе слушаются все доступные сигналы. По умолчанию на все из них (кроме SIGWINCH и SIGINFO) следует завершение работы. Но это легко можно переопределить создав в классе потока метод с именем сигнала. Например sigWinch.

В родительском процессе по умолчанию тоже перхватываются все сигналы. Это можно изменить выставив у класса параметр listenMasterSignals в false. В этом случае обрабатываться будет только SIGCHLD. Свои собственные обработчики можно легко добавить создав статический метод с названием m< имя сигнала >. Например mSigTerm.

Если дочерний процесс умрет по каким либо причинам, класс автоматически форкнется при запуске новой задачи. Это происходит незаметно и можно вообще об этом не задумываться. Просто инстанс не нужно пересоздавать в случае какой либо ошибки.

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

Все ресурсы используемые потоком или пулом потоков автоматически очищаются при вызове деструктора. Но их можно очистить принудительно если вызывать метод cleanup. В этом случае поток/пул больше нельзя использовать.

При стандартных настройках поток инициализируется заранее, сразу при создании класса. Если установить параметр prefork в false, то форк будет происходить только в момент запуска задачи.

Вообще настраиваемых параметров довольно много. Смена имени дочернего процесса после форка (параметр pName конструктора), таймаут на время выполнения задачи (timeoutWork), таймаут на максимальное время ожидания задач дочерним процессом (timeoutMaxWait), таймаут на время пре-инициализации (timeoutInit), размеры буферов для чтения сокетов (pipeReadSize, pipeMasterReadSize).
Можно отключить режим мультизадачности для потоков (multitask). В этом случае каждый раз по завершении задачи дочерний процесс будет умирать и форкаться заново для следующего запуска. Это заметно уменьшит производительность.

Код покрыт тестами и подробно документирован, примеры использования можно посмотреть и запустить в файле example.php.
Более сложные примеры с обработкой ошибок можно увидеть в коде юнит теста.

Есть режим отладки в котором выводится очень подробная информация о том, что именно и где творится.

Примеры использования


Основная фича — максимальная простота. Если вы хотите просто запустить что либо в отдельном «потоке» достаточно следующего кода:
class ExampleThread extends Thread
{
    protected function process()
    {
        // Some work here
    }
}

$thread = new ExampleThread();
$thread->wait()->run();

Если есть все необходимое для полноценной работы, то задача будет выполнена асинхронно. Если нет, то все будет по прежнему работать, но в синхронном режиме.

С передачей параметра и получением результата код будет выглядеть лишь чуть чуть сложнее:
class ExampleThread extends Thread
{
    protected function process()
    {
        return $this->getParam(0);
    }
}

$thread = new ExampleThread();
$thread->wait()->run(123);
$result = $thread->wait()->getResult();


Аналогично легким мановением руки добавляем обработку событий из потока:
class ExampleThread extends Thread
{
    const EV_PROCESS = 'process';

    protected function process()
    {
        $events = $this->getParam(0);
        for ($i = 0; $i < $events; $i++) {
            $event_data = $i;
            $this->trigger(self::EV_PROCESS, $event_data);
        }
    }
}

// Дополнительный аргумент.
$additionalArgument = 123;

$thread->bind(ExampleThread::EV_PROCESS, function($event_name, $event_data, $additional_arg)  {
    // обработка события
}, $additionalArgument);

$events = 10; // число событий, которое сгенерирует поток

// Чтобы не вызывать вручную ожидание потока перед первым вызовом,
// можно переопределить свойство preforkWait в TRUE в классе-наследнике
$thread->wait();

$thread = new ExampleThread();
$thread->run($events)->wait();


И наконец использование пула из восьми потоков с обработкой ошибок выполнения:
$threads = 8  // Число потоков
$pool = new ThreadPool('ExampleThread', $threads);

$num = 25;    // Количество задач
$left = $num; // Количество оставшихся задач

do {
    // Если в пуле есть свободные потоки
    // И у нас остались задачи для выполнения
    while ($pool->hasWaiting() && $left > 0) {
        // При запуске получаем id потока
        $threadId = $pool->run();
        $left--;
    }
    if ($results = $pool->wait($failed)) {
        foreach ($results as $threadId => $result) {
            // Успешно выполненная задача
            // Результат можно идентифицировать
            // по id потока ($threadId)
            $num--;
        }
    }
    if ($failed) {
        // Обработка ошибок выполнения.
        // Работа считается завершенной неуспешно
        // если дочерний процесс умер во время выполнения или
        // истек таймаут на выполнение задачи
        foreach ($failed as $threadId) {
            $left++;
        }
    }
} while ($num > 0);

// Завершаем все дочерние процессы. Очищаем ресурсы используемые пулом.
$pool->cleanup();


Результаты тестирования производительности



Тесты запускал на двух машинах с Ubuntu 11.04.
Первая — Intel Core i3 540 3.07 Ghz
Вторая — Intel Core i7 2600K 3.40 Ghz (убунту стоит на VMware виртуалке)

Результаты привожу просто чтобы можно было оценить рост производительности.
Опять же это средние результаты за серию из 10 повторов теста в jps (jobs per second — кол-во задач в секунду).

В качестве задачи потоки выполняют следующую фигню:
for ($i = 0; $i < 1000; $i++) {
    $r = mt_rand(0, PHP_INT_MAX) * mt_rand(0, PHP_INT_MAX);
}

Первый результат указан для синхронного режима работы (без форков).
18 и 20 потоков на первой конфигурации я не пробовал, так как уже для 12 началось падение производительности.
Число потоков Первая конфигурация Вторая
0 553 763
1 330 669
2 580 1254
4 1015 2188
8 1040 2618
10 1027 2719
12 970 2739
16 958 2904
18 - 2830
20 - 2730


То бишь производительность поднимается в 2-4 и более раза в зависимости от процессора!

Код, выполняющий серию тестов с нужными параметрами, лежит в файле examples/speed_test.php. Так что вы легко можете протестировать производительность и выбрать оптимальное число потоков у себя.



Ну и в завершение еще раз ссылка на исходники, возможно кто-то не заметил сверху:
github.com/Anizoptera/AzaThread

Буду очень рад если библиотека кому-либо пригодится. Любые фич-реквесты или обнаруженные баги можно оставлять на гитхабе, буду оперативно фиксить и улучшать библиотеку.

UPD:
Вышло большое обновление библиотеки и она переименована из CThread в AzaThread. В комментариях возмущались по поводу названия с «C». Так вот теперь библиотека называется AzaThread, использует пространства имен и поддерживает PSR-0 :)
В связи с этим немного поправил статью — код, название и ссылки на github.

UPD2:
Для AzaThread теперь есть пакет composer. Библиотека переехала к остальным открытым компонентам из Anizoptera CMF. А о новых наших разработках и обновлениях открытых компонентов мы пишем теперь на нашем блоге AzaGroup.ru.
Амаль Сэмелли @samally
карма
85,0
рейтинг 0,0
Android & Web developer
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (66)

  • 0
    Интересно, потестирую.
  • +11
    Таки наконец-то я почти что счастлив.
    • НЛО прилетело и опубликовало эту надпись здесь
      • –1
        Ок
      • НЛО прилетело и опубликовало эту надпись здесь
        • НЛО прилетело и опубликовало эту надпись здесь
          • НЛО прилетело и опубликовало эту надпись здесь
        • +6
          Естественно — а Yahoo и Wikipedia это маленькие бложики на убогих скриптах.
          • НЛО прилетело и опубликовало эту надпись здесь
            • +1
              Так именно для этих самых прикладных задач интернета и используют PHP. Различные скрипты и демоны этому сопутствуют.
              • НЛО прилетело и опубликовало эту надпись здесь
                • +2
                  Ну вы учитывайте в какое мы время живем — реальные проблемы с железными мощностями и временем исполнения в основном связаны с ресурсоемкими операциями с СУБД, а не с серверным языком, будь-то PHP или любой другой.
                • +4
                  Кроме того, далеко не во всех компаниях есть отдельный человек для каждой специализированной задачи, иногда одному человеку (например, php-программисту), приходится быть мастером на все руки — и сервера виртуализировать, и кластеризацию настраивать, и репликации, и собтвенно писать приложения и много-много прочего, в таком случае просто может не быть времени на то чтобы освоить тот же node.js хотя бы на базовом уровне, необходимом для интеграции простого решения, в таких случаях подход «вижимать все возможности из используемой технологии» очень даже оправдывает себя.
                  • НЛО прилетело и опубликовало эту надпись здесь
                    • 0
                      Плюсую, отчасти согласен, но с некоторыми поправками:
                      1. Всегда можно отказаться делать ту работу, которая не относится к вашим прямым обязанностям.
                      2. НО — иногда на такое стоит согласиться просто ради того чтобы повысить свои знания в определенной сфере — если бы я одно время не брался за такую работу, то знал бы намнного меньше.
                      3. Но не стоит НАДОЛГО отвлекаться от развития в своей главной профессиональной нише на побочные знания. Такие проекты полезны, если они не слишком долго длятся.
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • 0
                          Да, просто если конкретно вы видите для себя в этом пользу, то можно взять на себя больше чем полагается. Я благодаря такому решению многое узнал и многому научиился, но, повторюсь, таким можно заниматься очень недолго, только до того момента, когда получите необходимые по вашему мнению базовые знания в такой относительно побочной сфере.
                    • 0
                      Разве плохо открыть свой бизнес или стать (топ-)менеджером в чужой компании и понимать чем подчиненные занимаются? :)
                • 0
                  Вы знаете способ как сделать это на PHP более эффективно?
            • +4
              >>Ваши знания ограничены прикладными задачами интернета.
              Собственно говоря никто и не говорит что на PHP нужно писать ОС.
  • +1
    Спасибо за проделанную титаническую работу.
    Однозначно— качаю, пробую!
  • 0
    Довольно интересная библиотека. Буду пробовать.
  • 0
    Я так понимаю у вас запскалось cli-php? Есть ли смисл использовать тридинг вместе с тридингом на уровне web-сервера(thread-safe zts, mpm_worker)?
    • 0
      для запуска в режиме web асинхронных обработчиков я использую code.google.com/p/php-forker/
      • 0
        А на каких задачах вииграш ощутим? Я сам не програмист, но часто на серверах наблюдаю проблему когда при тупняке/локах в БД, количество процесов php/httpd растет, провоцируя рост LA/Memory/CS. Асинхроность поможет? Или посоветуйте другой вариант. Спасибо.
        • +3
          nginx + php-fpm не пробовали?
          • –2
            Не совсем понятно, как php-fpm решит проблему? Принудительное убийство чайлдов? На самом деле нужно что-то вроде connection pooling.
            • 0
              Меньшее количество занимаемой памяти на каждый обработчик. Решение, конечно, не качественное, но количественное, но и этого зачастую хватает, особенно когда возможности вертикального масштабирования исчерпаны, а горизонтальное требует существенных изменений в приложении.
            • 0
              Для connection pooling-a попробуйте beanstalk: github.com/kr/beanstalkd
        • 0
          ощутимо, например, при закачке списка страниц/картинок с другого сайта, когда соединение является одним из наибольших затрат.
          при тупняке/локах в БД данное решение вряд ли поможет.
        • 0
          >А на каких задачах вииграш ощутим?
          я бы поставил вопрос так: А на каких задачах использование асинхронных задач применимо?

          Это сложные расчетные или вычислительные задачи, такие как расчет оптимального пути при большом количестве данных, или генерация 1 000 000 лотерейных билетов. Реализация данных задач занимает больше, чем ожидаемый ответ от WEB сервера: 120 сек.

          Алгоритмов реализации подобных задач может быть несколько, один из них — это запуск через AJAX асинхронного процесса, который в файл сбрасывает состояние расчета (прогресс), как правило в статический файл в ввиде JSON. Клиентский скрипт, опять же через AJAX, опрашивает состояние расчета (отображая в прогрессбаре), и при окончании расчета осуществляет редирект на страницу результата.

          вот как-то так я и использовал
    • 0
      Библиотека предназначена для CLI. Для работы из под других SAPI скорее всего не подойдет.
  • +2
    делал похожее где-то 4 года назад
    тогда не было libevent
    обмен между тредами был реализован на неблокируемых сокетах.
    сейчас для асинхронного обмена использую gearman.org/
    • +1
      более того gearman можно использовать и для связок mysql+php и тд. что дает еще больший профит.
      • 0
        радует, что использую не в гордом одиночесстве
  • 0
    Чем вас не устроила связка
    www.php.net/manual/en/book.pcntl.php
    www.php.net/manual/en/book.sem.php
    www.php.net/manual/en/book.shmop.php
    Если используются всё те же форки?
    • +5
      Такая связка, как и другие подобные не подходит. Пришлось бы постоянно в цикле проверять наличие новых сигналов, событий, истечение таймаутов.

      LibEvent делает это значительно более эффективно. Коллбэки выполняющие обработку событий дергаются только в нужное время, в остальное не нагружая процессор. В Ubuntu libevent использует для этого системный вызов epoll.

      Кстати shmop используется в библиотеке, как один из вариантов передачи данных между процессами. По умолчанию он не задействован, так как оказался не самым эффективным, но его легко можно включить, если в вашей конфигурации он даст прирост производительности:
      CThread::$ipcDataMode = CThread::IPC_SHMOP;
      

      Хотя скорее всего в этом случае System V Memory queue (CThread::IPC_SYSV_QUEUE) будет все равно быстрее

      P.S.
      В состав библиотеки входят удобные врапперы над sysvmsg, sysvsem, sysvshm, shmop и libevent. Возможно кому-то они пригодятся отдельно от CThread.
  • 0
    За статью спасибо. Но все-таки это не настоящая многопоточность. А я то уже размечтался )
  • 0
    Почему через сокеты получилось быстрее чем через память shared memory? Должно ведь быть наоборот.
    И хотелось бы ещё увидеть тесты через unix socket file, который в том же mysql быстрее обычных TCP/IP сокетов.
    И почему в случае одного потока производительность падает чуть ли не в 2 раза?
    Использовался ли APC/xCache?
    • +4
      1. Для передачи пакетов-уведомлений используются сокеты. Соответственно при передаче сериализованных данных в сокетах они входят в состав такого пакета и читаются разом. Это особенно эффективно при передаче небольших объемов данных.
      В любом случае вы можете протестировать варианты передачи данных и если в вашем случае будет более эффективным какой либо вариант не по умолчанию, то выставить его.

      2. Парные сокеты и так создаются юниксовыми

      3. В случае одного потока появляются дополнительные накладные расходы (общение между процессами и т.п.), но реального распараллеливания задач не происходит. Мы все равно ждем пока поток завершит одну задачу, чтобы дать ему следующую.

      4. Все тесты были с использованием APC.
      • 0
        В этом тесте не видно прямо уж такого общения между потоками. Ну запустился поток, ну посчитал 1000 случайных чисел, а 200мс куда подевались то? Создание потока так много не отнимает ведь.
        • +3
          Видимо вы не до конца поняли как внутри происходит работа.

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

          То есть на каждую задачу происходит минимум два обмена данными между процессами. А за секунду в этом случае их случилось 660.
  • +4
    Почему вы форкающую библиотеку назвали CThread и всюду говорите о многопоточности?
    • +2
      Эта библиотека не является «оберткой вокруг форков». Она эмулирует работу с потоками, потому и называется CThread. Так что для упрощения я называю отдельным потоком совокупность инстанса класса, обеспечивающего эмуляцию работы потока, и форкнутого процесса, не теряющего связи с родительским.

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

      P.S.
      Вот например более примитивный аналог. Там класс называется еще проще — Thread.
      • –1
        Вы просто упрощаете работу с форками, а не эмулируете потоки. Назвали бы CFork, не вносили бы путаницу в терминологию.
        • +3
          Блин, хоть кто нибудь читает статью?

          Там в самом начале написано про эмуляции многопоточности в php, затем описано как именно и с помощью библиотека их эмулирует, какой функционал при этом доступен.
          CThread не предоставляет интерфейс для работы с форками, они закопаны далеко внутри и просто используются для асинхронного выполнения задачи. Увы никакой нормальной альтернативы тут форкам я не вижу.

          Путанницы при этом на самом деле нет, поскольку нет и настоящей многопоточности в php! Все библиотеки эмулирующие многопоточность так или иначе называют такой асинхронный процесс потоком. Не писать же каждый раз «эмуляция потока» или пул из 16 «эмуляций потока».

          Если бы библиотека использовала настоящие потоки, то соответственно и ни слова об эмуляции или форках не было.
          • –4
            Да, блин, читал.

            По-прежнему считаю, что вы вносите путаницу в терминологию и сумятицу в умы php-программистов, которые и так-то редко знают чем отличаются нити от процессов.

            Ну назвали бы CThreadEmulation что ли. Или как-то так.
            • +4
              Позвольте, те php-программисты, которые реально программисты уж как-нибудь осилят, а это вроде как не пособие о том, как написать сайт-визитку за 10 минут, что реально радует, потому как статьи про обработку ошибок и прочее — это немного другой уровень, который профессионалам не интересен, по понятным причинам.

              Если все статьи писать из расчета на самый низкий уровнь познаний, то ничего интересного почерпнуть не удастся никому, кроме новичков.

              Это как объяснять почему небо синее — не везде уместно.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Поддержу, реализация очень крута.
  • –2
    libevent это конечно круто, но вот есть одно но — ну не реализовать многопоточность в php! Зачем извращаться? Даже не начав читать я сразу подумал что речь скорее всего пойдет о форках. Ребят, ну будьте мужиками, ну освойте дополнительный язык программирования, который лучше подойдет для решения той или иной задачи. Посты в духе «многопоточности php» у меня относятся к категории «игры на php», «как из php сделать exe» и тому подобным. Можно, можно, но язык для этого не предназначен! И никакие cthread это не исправят. Gearman кстати сюда не относите, он не для этого был создан, а для «разделения труда».
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        Не стоит смешивать фронтенд и бекенд черт вас побери! PHP — был и есть язык лёгкой разработки web-приложений. Решения, требующие скорости, фоновой работы и тд — выходят за рамки php. И что это у вас за «масштабирование» такое аж «распараллеливанием»? Чего «распараллеливать» то? Уж не php-fpm ли вы имеете ввиду? Я вам не от балды говорю — просто я не только php знаю, в отличии от вас.
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            Вы даже не вникли в то, что я написал. И спасибо хабрасообществу за минусы в карму. Я лишь ещё раз убедился что тут сплошные профессионалы, которые готовы на php писать всё что угодно. Благо порог вхождения в язык весьма низок. Это радует, но не всегда — иногда огорчает. Когда понимаешь, что вокруг тебя мало программистов, которым можно доверить серьезный проект. Даже на таком, серьёзном, казалось бы, ресурсе. Припоминаются слова великого русского поэта Александра Блока — «Только большие задачи должен ставить себе писатель. Ставить смело, не смущаясь своими личными малыми силами». Так вот это про вас. Выкиньте свою лень и сядьте за учебники. Освойте программирование в конце то концов! Это ведь как математика в школьном курсе — надо, но сложно. Попробую выразиться доступным для вас языком — как вы думаете программисты Delphi для создания сайтов тоже используют Delphi? Но ведь вполне могут…

            И не верю что вы знаете python, иначе бы не занимались расфоркиванием на php
            • НЛО прилетело и опубликовало эту надпись здесь
            • +1
              У программистов Delphi, наверное, другие задачи стоят обычно, а не веб-разработка. И не знаю как на Delphi, но на C писать демонов лично мне было сложнее, чем на PHP, хотя казалось бы те же самые системные вызовы используются по сути, но вот когда доходит до того, что демон должен делать, то на С резко падает скорость разработки.
              • 0
                И где вы в моих постах увидели призыв к C? Тот же Perl например, весьма хорош для создания демонов, в т.ч. multi-threading
                • 0
                  Я увидел призыв к «не PHP», а C, вроде как, довольно распространен для написания демонов в том числе и из-за скорости. Вы же прежде всего из-за неё призываете отказаться от PHP? А Perl, по идее, не должен быть сильно быстрее PHP, ведь они оба интерпретируемые. Многопоточность — да, не хватает PHP.
                  • 0
                    Perl и Php сравнивать вообще нельзя — это два абсолютно разных языка, по принципу работы и по назначению. Сравнивать Perl и Php это почти как сравнивать JSF и Java, в принципе первые версии php были написаны на perl и подавались как фреймворк для написания веб-приложений, поэтому такое сравнение оправдано. Perl — почти системный язык. Php содержит в себе множество функций и модулей, perl не содержит почти ничего, лишь необходимый минимум (циклы/хеши/модули/массивы/IO/ссылки), слегка больше чем C. А весь остальной функционал реализуется сообществом в виде компилируемых модулей. В этом он сроднен с питоном, там необходимый функционал тоже не заложен заранее. Просто попробуйте запустить в командной строке пустой php-скрипт и пустой perl-скрипт, и сами оцените правильность своих слов насчет «быстрее». При запуске php проиграет по скорости раз в 10, при отжоре памяти php проиграет раз в 10 и при скорости он тоже проиграет, ибо напичкан функционалом так, что почти на любую мелочь есть функция. В вебе не нужна многопоточность — юзайте курл и не блокируемые сокеты.
          • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          PHP давно уже может и прекрасно работает для фоновых процессов и демонов, обеспечивая хорошую скорость выполнения. Все это сопутствует серьезным веб проектам и прекрасно укладывается в рамки php.

          Распараллеливать же можно очень многие процессы. Сложная обработка изображений, видео, больших объемов текста и многое другое. Эти процессы очень эффективно распараллеливать на одной машине и масштабировать на несколько.

          О каком смешении фронтенда и бэкенда вообще идет речь? Причем здесь php-fpm?

          Не стоит кичиться знанием «не только php», очень многие здесь знают несколько языков и это не мешает осознанно делать выбор в сторону php.
    • +1
      Язык типа C++/Java/C# или даже Python/Ruby нормальному пэхэпэшнику освоить не проблема. Проблема (по крайней мере у меня) с инфраструктурой. Рецепты типа «apt-get install apache2, mysql-server, php5 — установка, apt-get update && apt-get upgrade — обновления. » почему-то не приводятся обычно в туториалах.

      Локально всё худо-бедно работает, но как представляю, что я на продакшен сервере буду компилировать веб или fast-cgi сервер или вообще транслятор языка… Аж мурашки по коже.
  • НЛО прилетело и опубликовало эту надпись здесь
  • –1
    Святые угодники, когда вы уже наконец-то научитесь использовать неймспейсы? PSR-0? Два с половиной года уже прошло с момента релиза 5.3 а вас хлебом не корми, дай все классы начинать на C

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.