Сложилось общее мнение, что из-за отсутствия в PHP потоков, как в C++ или Java, PHP не является многозадачным языком. Грубо говоря нельзя исполнять несколько команд одновременно. В результате многие разработчики выходили из положения с помощью эмуляции в виде асинхронных сокетов(Asynchronous Sockets) или мультикурл (curl_multi_init), некоторые использовали библиотеку pcntl_fork которая не входит в стандартную сборку PHP. Да, PHP не поддерживает обработку потоков, но он может быть многозадачным.
Чем плохо способы с сокетами или curl? Представьте, что у вас высоко нагруженный сервер, вы запускаете скрипт и он начинает загружать вебсервер еще сильнее. Вы обращаетесь сначала к серверу, тот запускает PHP обработчик, который и исполняет скрипт. Подумайте, не лучше ли исключить вебсервер из исполнения?
В PHP 5ой версии появились функции stream_select и proc_open, которые позволяют создавать и опрашивать потоки наподобие сокетов, но исполняя программу локально.
Надо сразу оговориться что для основной программы и потока понадобятся разные файлы.
<?php
$timeout=10; //раз во сколько секунд опрашивать потоки(при 0 мы будем опрашивать //потоки постоянно, но этот режим потребляет много памяти $streams=array();//массив потоков $handles=array();//массив ссылок на потоки $all_pipes=array();//массив настроек для каждого потока $maxthreads=10;//количество потоков
for ($id=0; $id <= $maxthreads; $id++) { $error_log="/tmp/error" . $id . ".log"//файл ошибок соответствует номеру потока $descriptorspec=array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("file", $error_log, "w") ); $cmd='php ./thread.php '.$id;//команда которую вызывает поток, //в данном случае мы вызываем исполнение скрипта потока $handles[$id]=proc_open($cmd, $descriptorspec, $pipes);//создаем поток $streams[$id]=$pipes[1]; $all_pipes[$id]=$pipes; }
while (count($streams)) {//пока все потоки не исполнились $read=$streams; stream_select($read, $w=null, $e=null, $timeout);//опрашиваем потоки foreach ($read as $r) { $id=array_search($r, $streams); echo stream_get_contents($all_pipes[$id][1]);//выводим на экран все что возращает скрипт if (feof($r)) {//если поток выполнился возвращается EOF //закрываем поток fclose($all_pipes[$id][0]); fclose($all_pipes[$id][1]); $return_value=proc_close($handles[$id]); unset($streams[$id]);//удаляем информацию о нем из массива } } } ?> |
Как вы видите мы не обращаемся к веб серверу, это позволяет экономить процессорное время, что соответственно увеличивает производительность.
Всегда ваш,
Александр 7ion.