📜 ⬆️ ⬇️

Another PHP threading implementation

So ... let's get started.
Recently, I immediately met 2 implementations of multithreading on Habré. A little thought, I decided to write my own version.
But since I do not have the opportunity to use the PCNTL library, I had to pervert ...

Task: implementation of multithreading in PHP (threads)

Cost: no PCNTL module (build w PCNTL)
')
Solution: pure PHP + Unix (pure PHP + Unix)

How it was ... And how it became.

File application.php
This is the class itself that implements the trids (threads) and allows these threads and the parent to exchange variables. How this happens will tell later.
<?
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);
?>



And this is a small test, with which we can check whether everything works. =)
File 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);
?>



Threat Do not hit hard, it is, so to speak, my first (almost) post ...
PS Threat This is a cross-post from my blog ( AlexSnet.ru )

UPD: At the request of the habra people.

Where to use it and where it is not worth using it


This solution is resource demanding, since the launch of another PCP process is a very demanding task.
In case you can use the console or run the script from Cron, it is better to use the coldFlame coldFlame solution ( PHP multiprocess daemons ). But here, too, there is a pitfall and his name is PCNTL .
PCNTL (Process Control) requires a special assembly and does not work under Win-systems.

My option should be used only when it is not possible to use the method already mentioned above.

Source: https://habr.com/ru/post/40545/


All Articles