Global incremen in thread PHP - php

I am running 4 threads running in same time. (Threads are running work() function in same time in this case)
global $i;
$i = 1;
function work($address) {
while($i < 1000) {
$i++;
----
if($i == something) some job...
----
}
}
For some reason this don't do the job.
Threads do sometimes same circle in while, so I have later some duplicate values. (probably they have some critical section)
Any idea how to fix this ?

The counter object must be thread safe, it must also employ synchronized methods.
Follows is an example of such code:
<?php
class Counter extends Threaded {
public function __construct($value = 0) {
$this->value = $value;
}
/** protected methods are synchronized in pthreads **/
protected function increment() { return ++$this->value; }
protected function decrement() { return --$this->value; }
protected $value;
}
class My extends Thread {
/** all threads share the same counter dependency */
public function __construct(Counter $counter) {
$this->counter = $counter;
}
/** work will execute from job 1 to 1000, and no more, across all threads **/
public function run() {
while (($job = $this->counter->increment()) <= 1000) {
printf("Thread %lu doing job %d\n",
Thread::getCurrentThreadId(), $job);
}
}
protected $counter;
}
$counter = new Counter();
$threads = [];
while (($tid = count($threads)) < 4) {
$threads[$tid] = new My($counter);
$threads[$tid]->start();
}
foreach ($threads as $thread)
$thread->join();
?>
work() seems superfluous, this logic should be in the ::run function most likely.

Related

Pthread For PHP Issue

I am using PThreads for multi-threading in php. I have installed and run it successfully on my XAMPP server on windows.
I have 100K records in my database and I want to run 20 threads in parallel.Every thread will call 5k record from database and process them.Here is my code for this
require('mailscript.php');
class My extends Thread{
function __construct() {
$this->mailscript = new mailscript();
}
function run(){
$this->mailscript->runMailScript(5000);
}
}
for($i=0;$i<20;$i++){
$pool[] = new My();
}
foreach($pool as $worker){
$worker->start();
}
foreach($pool as $worker){
$worker->join();
}
When I run this code it only run for approx 600 records per thread maximum.Is there any limit issue for number of threads in PThreads. What is the issue please help me
hie, here is how I would handle pthreads with your example with a collection method to be used if nescessary. Hope this will help you.
/*pthreads batches */
$batches = array();
$nbpool = 20; // cpu 10 cores
/* job 1 */
$list = [/* data1 */];
$batches[] = array_chunk($list, 5000);
/* job 2 */
$list2 = [/* data2 */];
$batches[] = array_chunk($list2, 10000);
/*final collected results*/
$resultFinal = [];
/* loop across batches */
foreach ($batches as $key => $chunks) {
/* for intermediate collection */
$data[$key] = [];
/* how many workers */
$workCount = count($chunks);
/* set pool job up to max cpu capabilities */
$pool = new Pool($nbpool, Worker::class);
/* pool cycling submit */
foreach (range(1, $workCount) as $i) {
$chunck = $chunks[$i - 1];
$pool->submit(new processWork($chunck));
}
/* on collection cycling */
$collector = function (\Collectable $work) use (&$data) {
/* is worker complete ? */
$isGarbage = $work->isGarbage();
/* worker complete */
if ($isGarbage) {
$data[$key] = $work->result;
}
return $isGarbage;
};
do {
/* collection on pool stack */
$count = $pool->collect($collector);
$isComplete = count($data) === $workCount;
} while (!$isComplete);
/* push stack results */
array_push($resultFinal, $data);
/* close pool */
$pool->shutdown();
}
class processWork extends \Threaded implements \Collectable {
private $isGarbage;
private $process;
public $result;
public function __construct($process) {
$this->process = $process;
}
public function run() {
$workerDone = array();
foreach ($this->process as $k => $el) {
/* whatever stuff with $this->process */
}
$this->result = $workerDone;
$this->isGarbage = true; // yeah, it s done
}
public function isGarbage(): bool {
return $this->isGarbage;
}
}

PHP - PTHREAD Worker Threads not executing concurrently

I am working on improving a process in php so I resorted into using multithreading using Worker to manage my threads. But the threads in the worker executes one after the other not concurrently.
This is my sample code
namespace App\Engine\Threads\ThreadClass;
class StatePaperAttendancePDFThread extends \Threaded
{
private $write_folder_name;
private $center_code;
private $paper_id;
private $title;
public function __construct($write_folder_name, $center_code, $paper_id, $title)
{
$this->write_folder_name = $write_folder_name;
$this->center_code = $center_code;
$this->paper_id = $paper_id;
$this->title = $title;
}
public function run(){
echo " Retrieving paper attendance ".$this->center_code." ".$this->paper_id." ".\Thread::getCurrentThreadId()." ".date("H:i:s:u").PHP_EOL;
$artisan = 'C:/xampp/htdocs/attendance/artisan';
$cmd = "php $artisan attendancereport:center $this->write_folder_name $this->center_code $this->paper_id $this->title";
$return = exec($cmd, $output, $return_var);
echo $return;
}
}
foreach ($centers as $i=>$center){
$center_code = $center->getCenterCode();
$thread = new StatePaperAttendancePDFThread($folder_name, $center_code, $paper_id, $title);
$worker->stack($thread);
}
$worker->start(PTHREADS_INHERIT_ALL ^ PTHREADS_INHERIT_CLASSES);
$worker->shutdown();
but when I monitor it from the CLI using the time been printed I can see that none of the threads starts together. They all starts with some seconds interval
Please what am I missing
I was able to solve my problem by creating a customized Thread Pool Executor as below. Please I am open to suggestions and Improvement
class ThreadPoolExecutor{
private $poolSize;
private $threadPool;
private $done = false;
private $workingThreads;
public function __construct($poolSize, array $threadPool)
{
$this->poolSize = $poolSize;
$this->threadPool = $threadPool;
}
public function execute()
{
$this->parametersOk();
try {
while (!empty($this->threadPool)) {
$this->extractThreads();
foreach ($this->workingThreads as $thread) {
$thread->start(PTHREADS_INHERIT_ALL ^ PTHREADS_INHERIT_CLASSES);
}
foreach ($this->workingThreads as $thread) {
$thread->join();
}
}
$this->done = true;
} catch (\Exception $ex) {
var_dump($ex->getMessage());
}
}
private function parametersOk()
{
if (!is_array($this->threadPool))
throw new \RuntimeException("threadPool expected to be an array of threads");
if (count($this->threadPool) <= 0)
throw new \RuntimeException("expected at least an element in threadPool");
foreach ($this->threadPool as $thread) {
if (!is_subclass_of($thread, \Thread::class, false)) {
throw new \RuntimeException(" an element of threadPool does not extend class \\Thread");
}
}
if ($this->poolSize > count($this->threadPool)) {
throw new \RuntimeException("The number of threads set to execute can not be greater than the threadPool");
}
return true;
}
private function extractThreads()
{
$this->workingThreads = [];
$this->workingThreads = array_slice($this->threadPool, 0, $this->poolSize);
for ($i = 0; $i < count($this->workingThreads); $i++) {
array_shift($this->threadPool);
}
}
public function isDone()
{
return $this->done;
}
}
I will appreciate any addition or correction to this.

how do I remove all references to stackable objects with PHP pthreads?

I am experimenting with pthreads in PHP. Referencing Joe's gist covering pools, I create a pool of worker threads, and submit instances of stackable objects. The threads and work all go as I expect, however it seems that the main thread/context does not (fully) dereference the Stackable objects, so memory usage increases indefinitely as it keeps more and more instances around.
It does seem to clear/nullify all of the properties of the stackable object, so memory usage doesn't quickly go through the roof, but it does increase forever, so this effectively can't be used for a long-running process. I hope I am just doing something wrong. Here is sample code that will demonstrate what I mean:
class W extends Worker {
public function run(){}
}
class S extends Stackable {
public $id;
public function run() {
$this->id = uniqid();
}
public function __destruct () {
// $this->id will be null here when the main thread destroys its copy of this
if ($this->id === null) {
echo "nullified stackable destroyed\n";
} else {
echo "stackable {$this->id} destroyed\n";
}
}
}
$pool = new Pool(3, W::class);
$i = 0;
while ($i++ < 10) {
$pool->submit(new S());
}
sleep(1); // to let threads finish
$pool->collect(function (S $s) {
echo "collected stackable {$s->id}\n";
return true;
});
$pool->shutdown();
echo "script exit - here come the destructions of all the accumulated stackables\n";
Many improvements have come to pthreads v3 as part of the upgrade for PHP7.
You will find the PHP7 version of this code works as expected:
<?php
class W extends Worker {
public function run(){}
}
class S extends Threaded implements Collectable {
public $id;
public function run() {
$this->id = uniqid();
$this->garbage = true;
}
public function __destruct () {
if ($this->id === null) {
echo "nullified stackable destroyed\n";
} else {
echo "stackable {$this->id} destroyed\n";
}
}
public function isGarbage() : bool { return $this->garbage; }
private $garbage = false;
}
$pool = new Pool(3, W::class);
$i = 0;
while ($i++ < 10) {
$pool->submit(new S());
}
while ($pool->collect(function (S $s) {
if ($s->isGarbage()) {
echo "collected stackable {$s->id}\n";
}
return $s->isGarbage();
})) continue;
$pool->shutdown();
echo "script exit - here come the destructions of all the accumulated stackables\n";
It is recommended that new projects use PHP7 and pthreads v3, it is vastly superior to PHP5 and pthreads v2.

How do I set the procss blocked for waiting for a signal in PHP

I`m writing a Timer script,using a signal.Every 1 second send a SIGALRM to the process,then catch the signal and check whether the there is a task to do.
I use pcntl_alarm(1) to send the signal,but the process excute-and-quit,before receive the signal.
I think whether there is a method to set the prcess blocked waiting for the signal.I have used base_event,but its much heavy.
So anybody can help me.Thanks a lot.
That`s my script(Sorry for the chinesse ^_^):
<?php
/**
*定时器
*/
class Timer
{
//保存所有定时任务
public static $task = array();
//定时间隔
public static $time = 1;
/**
*开启服务
*#param $time int
*/
public static function run($time = null)
{
if($time)
{
self::$time = $time;
}
self::installHandler();
pcntl_alarm(1);
do{ sleep(2); }while(true);
}
/**
*注册信号处理函数
*/
public static function installHandler()
{
echo "installHandler\n";
pcntl_signal(SIGALRM, array('Timer','signalHandler'),false);
pcntl_alarm(1);
}
/**
*信号处理函数
*/
public static function signalHandler()
{
self::task();
}
/**
*执行回调
*/
public function task()
{
if(empty(self::$task))
{
return ;
}
foreach(self::$task as $time => $arr)
{
$current = time();
$func = $arr['func'];
$argv = $arr['argv'];
$interval = $arr['interval'];
$persist = $arr['persist'];
if($current == $time)
{
call_user_func_array($func, $argv);
}
if($persist)
{
self::$task[$current+$interval] = $arr;
}
unset(self::$task[$time]);
}
pcntl_alarm(self::$time);
}
/**
*添加任务
public static function add($interval, $func, $argv,$persist = false)
{
if(is_null($interval))
{
return;
}
$time = time()+$interval;
self::$task[$time] = array('func'=>$func, 'argv'=>$argv, 'interval'=>$interval, 'persist'=>$persist);
}
/**
*删除所有定时器任务
*/
public function dellAll()
{
self::$task = array();
}
}
Now, I know the answer even though so many times has passed away for I had other jobs to finish...sorry for the late.So my answer is very simple.
sleep
is right for blocking a process, then the process receives a signal,and what I have missed is never capture it...so use
pcntl_signal_dispatch
function in a loop is exactly the way.

reusing worker threads pthreads

I have run into a situation with pthreads.Consider the following script:
<?php
class W extends \Worker {
public function run()
{
echo "worker started\n";
}
}
clasds S extends \Stackable {
public function run()
{
echo "stackable executed\n";
}
}
class x{
protected $workers;
protected $i;
public function __construct()
{
$this->workers = array();
$this->i = 0;
}
public function go()
{
$thread = $this->spawn();
$j = new S;
$thread->stack($j);
//$thread->shutdown();
}
public function spawn()
{
$this->i !== 0 ? $n=$this->i++ : $n=$this->i;
$thread = new W;
$this->workers[$n] = $thread;
$thread->start();
return $thread;
}
}
$exe = new x;
$exe->go();
php crashes.2 ways to solve the issue, either:
uncommenting
$w->shutdown();
which means the workers one creates are not reusable, or commenting out
$this->c[$n] = $w;
which means not saving workers in an array.
I do not understand what is going on here.must one call shutdown on a worker?why does attempting to store
the worker in an array lead to a crash?

Categories