Итак… Приступим.
В последнее время я встретил сразу 2 реализации многопоточности на Хабре. Немного подумав я решил написать и свой вариант.
Но так как у меня нет возможности использовать PCNTL библиотеку, то мне пришлось извратиться…
Задача: реализация многопоточности на PHP (threads)
Издержки: нет модуля PCNTL ( build w/o PCNTL )
Решение: чистый PHP + Unix ( pure PHP + Unix )
Как это было… И как это стало.
Файл application.php
Это сам класс, реализующий триды (потоки) и позволяющий этим потокам и родителю обмениваться переменными. Как это происходит расскажу попозже.
А это маленький тест, с помощью которого мы можем проверить все ли работает. =)
Файл threads.php
ЗЫ Сильно не бейте, это, так сказать мой первый (почти) пост…
ЗЫ ЗЫ Это кросс-пост из моего блога (AlexSnet.ru)
UPD: По просьбе хабралюдей.
Данное решение требовательно к ресурсам, так как запуск еще одного процесса ПХП — очень требовательное к ресурсам задание.
В случае, если Вы можете использовать консоль или запускать скрипт из Cron'a лучше использовать решение coldFlamecoldFlame (Многопроцессовые демоны на PHP). Но тут тоже есть подводный камень и имя ему — PCNTL.
PCNTL (Process Control) требует специальной сборки и не работает под Win-системами.
Мой вариант следует использовать только тогда, когда нет возможности использовать уже названный выше метод.
В последнее время я встретил сразу 2 реализации многопоточности на Хабре. Немного подумав я решил написать и свой вариант.
Но так как у меня нет возможности использовать PCNTL библиотеку, то мне пришлось извратиться…
Задача: реализация многопоточности на PHP (threads)
Издержки: нет модуля PCNTL ( build w/o PCNTL )
Решение: чистый PHP + Unix ( pure PHP + Unix )
Как это было… И как это стало.
Файл application.php
Это сам класс, реализующий триды (потоки) и позволяющий этим потокам и родителю обмениваться переменными. Как это происходит расскажу попозже.
<?
class Application
{
public $child = false;
private $file;
private $tmpdir;
private $children = array();
private $vars = array();
public function __construct($argv,$argc)
{
$GET = array();
$this->file = str_replace(' ','\ ',getcwd()).'/'.$argv[0];
for($i=1;$i<$argc;$i++)
{
if(substr($argv[$i],0,1)=='-' and ( isset($argv[($i+1)]) and substr($argv[($i+1)],0,1)!=='-'))
{
$GET[substr($argv[$i],1)] = $argv[($i+1)];
$i++;
}
else
{
$GET[substr($argv[$i],1)] = true;
}
}
$this->vars = $GET;
if(isset($this->vars['tmpdir']))
{
$this->child = $this->vars['pid'];
$this->tmpdir = $this->vars['tmpdir'];
}
else
{
$this->tmpdir = '/tmp/'.md5($this->file . time());
mkdir($this->tmpdir);
}
mkdir($this->tmpdir.'/vars');
}
public function __destruct()
{
if($this->child == false)
{
if(file_exists($this->tmpdir.'/vars/'))
{
$vars = scandir($this->tmpdir.'/vars/');
foreach($vars as $var) if(strlen($var)>3)unlink($this->tmpdir.'/vars/'.$var);
rmdir($this->tmpdir.'/vars/');
}
if(file_exists($this->tmpdir.'/threads/')) rmdir($this->tmpdir.'/threads/');
rmdir($this->tmpdir);
}
else unlink($this->tmpdir.'/threads/'.$this->child.'.pid');
}
public function __get($var)
{
$val = false;
if(file_exists($this->tmpdir.'/vars/'.md5($var)))
{
$val = file_get_contents($this->tmpdir.'/vars/'.md5($var));
$val = unserialize($val);
}
return $val;
}
public function __set($var,$val)
{
$fp = fopen($this->tmpdir.'/vars/'.md5($var), "w");
if (flock($fp, LOCK_EX))
{
fwrite($fp, serialize($val));
flock($fp, LOCK_UN);
}else $this->{$var} = $val;
fclose($fp);
}
public function startThreads($count=0)
{
mkdir($this->tmpdir.'/threads');
for($i=1;$i<=$count;$i++)
{
$pid = $this->tmpdir.'/threads/'.$i.'.pid';
$this->children[$i]['pid'] = popen("php {$this->file} -tmpdir {$this->tmpdir} -pid {$i} > {$pid}&",'r');
}
}
public function childs()
{
$dd = 0;
$darr = scandir($this->tmpdir.'/threads/');
foreach($darr as $d) if($d!='.' and $d!='..') $dd++;
return $dd;
}
public function write($args,$pid=false)
{
if(!is_array($args)) $args = array($args);
$str = serialize($args);
$f = fopen($this->tmpdir.'/'.$this->child.'.pid','w');
fwrite($f,$str);
fclose($f);
}
}
$Application = new Application($argv,$argc);
?>
А это маленький тест, с помощью которого мы можем проверить все ли работает. =)
Файл threads.php
<?
include "../application.php";
if( $Application->child !== false )
{
// Child
print 'Start at ' . date("H:i:s") . chr(10);
print 'I\'m child #' . $Application->child . chr(10);
sleep(rand(0,10));
$Application->MyVar++;
print 'Stop at ' . date("H:i:s") . chr(10);
}
else
{
// Parent
$Application->MyVar = 0;
print 'I\'m parent. ' . $Application->child . chr(10);
$Application->startThreads(10);
$cur_c = 0;
$las_c = 10;
while( ($cur_c = $Application->childs()) > 0)
{
if($cur_c != $las_c)
{
print 'There are ' . $cur_c . ' childs on fly.' . chr(10);
print 'MyVar: ' . $Application->MyVar . chr(10).chr(10);
}
$las_c = $cur_c;
sleep(1);
}
}
print 'MyVar: ' . $Application->MyVar . chr(10).chr(10);
?>
ЗЫ Сильно не бейте, это, так сказать мой первый (почти) пост…
ЗЫ ЗЫ Это кросс-пост из моего блога (AlexSnet.ru)
UPD: По просьбе хабралюдей.
Где это использовать и где это использовать не стоит
Данное решение требовательно к ресурсам, так как запуск еще одного процесса ПХП — очень требовательное к ресурсам задание.
В случае, если Вы можете использовать консоль или запускать скрипт из Cron'a лучше использовать решение coldFlamecoldFlame (Многопроцессовые демоны на PHP). Но тут тоже есть подводный камень и имя ему — PCNTL.
PCNTL (Process Control) требует специальной сборки и не работает под Win-системами.
Мой вариант следует использовать только тогда, когда нет возможности использовать уже названный выше метод.