Разработка многозадачных приложений на PHP V5 (исходники)Источник: IBM developerWorks Кэмерон Лэйрд
PHP не поддерживает обработку потоков. Несмотря на это, и в противоположность мнению большинства PHP-разработчиков, с которыми я общался, PHP-приложения могут быть многозадачными. Начнем с выяснения того, что "многозадачность" и "поточность" означают для PHP-программирования. Многообразие параллелизмаСначала отложим в сторону случаи, лежащие вне русла главной темы. У PHP сложные взаимоотношения с многозадачностью или параллелизмом. На верхнем уровне PHP постоянно вовлечен в многозадачность - стандартные установки PHP на сервере (например, модуль Apache) используются многозадачным способом. То есть несколько клиентских приложений (Web-браузеров) могут одновременно запросить одну и ту же PHP-страницу, и Web-сервер возвратит ее всем более или менее одновременно. Одна Web-страница не блокирует передачу другой, хотя они могут немного мешать друг другу при работе с такими ограниченными ресурсами как память сервера или пропускная способность сети. Таким образом, системное требование обеспечения параллелизма может вполне допускать основанные на PHP решения. В терминах реализации PHP возлагает на Web-сервер ответственность за параллелизм. Параллелизм на клиентской стороне под названием Ajax тоже привлек внимание разработчиков в последние несколько лет. Хотя значение Ajax стало несколько неясным, одним из аспектов этой технологии является то, что браузер может одновременно выполнять вычисления и оставаться чувствительным к таким действиям пользователя, как выбор пунктов меню. Это действительно отчасти многозадачность. Закодированный на PHP Ajax делает это, но без какого-либо специального участия PHP; интегрированные среды Ajax для других языков работают точно также. Третьим примером параллелизма, который только поверхностно затрагивает PHP, является PHP/TK. PHP/TK - это расширение PHP, предоставляющее переносимые связывания графического интерфейса пользователя (Graphical User Interface - GUI) ядру PHP. PHP/TK позволяет создавать настольные GUI-приложения, написанные на PHP. Его основанные на событиях аспекты моделируют форму параллелизма, которую легко изучить, и она меньше подвержена ошибкам, чем работа с потоками. Опять же, параллелизм "унаследован" от дополнительной технологии, а не является фундаментальной функциональностью PHP. Было несколько экспериментов по добавлению поддержки поточности в сам PHP. Насколько я знаю, ни один не был удачным. Однако ориентированные на события интегрированные среды Ajax и PHP/TK показывают, что события могут еще лучше выразить параллелизм для PHP, чем это делают потоки. PHP V5 доказывает это. PHP V5 предлагает stream_select()В стандартном PHP V4 и более ранних версиях вся работа PHP-приложения должна выполняться последовательно. Если программе нужно извлечь цену товара с двух коммерческих сайтов, например, она запрашивает первую цену, ждет получения ответа, запрашивает вторую цену и ждет опять. Что, если бы программа могла выполнять несколько задач одновременно? Она завершалась бы лишь за часть того времени, которое необходимо при последовательной работе. Первый примерНовая функция Листинг 1. Одновременный запрос нескольких HTTP-страниц
Если выполнить эту программу, отобразится примерно следующая информация: Листинг 2. Типичная информация, выводимая программой из листинга 1
Важно понимать, что здесь происходит. На высоком уровне первая программа выполняет несколько HTTP-запросов и получает страницы, которые передает ей Web-сервер. Хотя реальное приложение, наверное, запрашивало бы несколько различных Web-серверов (возможно google.com, yahoo.com, ask.com и т.д.), этот пример передает все запросы на наш корпоративный сервер на Phaseit.net просто ради уменьшения сложности. Запрошенные Web-страницы возвращают результаты после переменной задержки, показанной ниже. Если бы программа выполняла запросы последовательно, для ее завершения понадобилось бы около 15+12+9+6+3 (45) секунд. Как показано в листинге 2, на самом деле она завершается за 15 секунд. Утроение производительности - это отличный результат. Такое стало возможно благодаря
Сервер задержки реализован на CGI, как показано ниже. Листинг 3. Реализация сервера задержки
Хотя конкретная реализация в листинге 3 предназначена для UNIX®, почти все сценарии данной статьи с тем же успехом применимы для установок PHP в Windows® (особенно после Windows 98) или UNIX. В частности, с листингом 1 можно работать на любой операционной системе. Linux® и Mac OS X являются вариациями UNIX, и весь приведенный здесь код будет работать в обеих системах. Запросы к серверу задержки выполняются в следующем порядке: Листинг 4. Последовательность выполнения процесса
Целью Обработка продолжается таким же образом. Программа блокируется в Обратите внимание на то, что при этом нет дополнительной нагрузки на CPU хост-компьютера. Нет ничего необычного в том, что сетевые программы, выполняющие Что нужно знать о stream_select()Подобное основанное на событиях программирование не является элементарной задачей. Хотя листинг 1 и уменьшен до самых основных моментов, любое кодирование, базирующееся на обратных вызовах или координации (что является необходимым в многозадачных приложениях) будет менее привычным по сравнению с простой процедурной последовательностью. В данном случае наибольшая трудность заключена в массиве Такую методику запросов можно использовать из любого числа внешних Web-сайтов, удостоверяясь в том, что программа будет получать каждый результат как можно быстрее, не ожидая других запросов. Фактически, данная методика корректно работает с любым TCP/IP-соединением, а не только с Web (порт 80), то есть в принципе вы можете управлять извлечением LDAP-данных, передачей SMTP, SOAP-запросами и т.д. Но это не все. PHP V5 управляет различными соединениями как "потоками" (stream), а не простыми сокетами. Библиотека PHP Client URL (CURL) поддерживает HTTPS-сертификаты, исходящую FTP-загрузку, куки и многое другое (CURL позволяет PHP-приложениям использовать различные протоколы для соединения с серверами). Поскольку CURL предоставляет интерфейс stream, с точки зрения программы соединение прозрачно. В следующем разделе рассказывается, как Для Кроме того, в Локальный параллелизм PHPПример и основная часть обсуждения выше были посвящены тому, как управлять несколькими удаленными ресурсами одновременно и получать результаты по мере их появления, а не ожидать обработки каждого в порядке первоначальных запросов. Это, несомненно, важное применение параллелизма PHP. Иногда реальные приложения можно ускорить в десять и более раз. Что если замедление происходит поближе? Есть ли способ ускорить получение результатов в PHP при локальной обработке? Есть несколько. Пожалуй, они еще менее известны, чем ориентированный на сокеты подход в листинге 1. Этому есть несколько причин, в том числе:
Иногда можно добиться большего. Предположим, что PHP-страница должна вычислить два биржевых курса, возможно, сравнить их, а используемый хост-компьютер является многопроцессорным. В данном случае мы можем почти удвоить производительность, назначив два отдельных, выполняющихся продолжительное время вычисления различным процессорам. В мире PHP-вычислений такие примеры являются редкостью. Однако поскольку я больше нигде не нашел точного описания, хочу привести здесь пример подобного ускорения. Листинг 5. Реализация сервера задержек
Данная программа выведет на экран следующую информацию:
Смысл заключается в том, что PHP запустил два независимых субпроцесса, получил данные от первого, а затем от второго, хотя последний стартовал раньше. Если хост-компьютер является многопроцессорным, а операционная система корректно настроена, она сама заботится о назначении различных субпрограмм разным процессорам. Это один из способов использования преимуществ многопроцессорных машин в PHP. РезюмеPHP поддерживает многозадачность. PHP не поддерживает обработку потоков так, как это делают другие языки программирования, например Java или C++, но приведенные выше примеры показали, что PHP имеет более высокий потенциал для ускорения работы, чем многие себе представляют. |