I cannot use monolog logger inside Thread method run.
class MyThread extends Thread
{
public function run()
{
echo 'hihi', PHP_EOL;
$log = new Logger('MyApp');
$log->pushHandler(
new StreamHandler('php://stdout', Logger::INFO)
);
$log->addInfo("hoho");
echo 'haha', PHP_EOL;
}
}
$thread = new MyThread();
if ($thread->start()) {
$thread->join();
echo 'hehe', PHP_EOL;
}
Output:
hihi
hehe
Here PHP pthreads and SQLite3 and here pthread Thread objects reset their state somebody says that I can only use objects inerited from Stackable, Thread or Worker inside my class inherited from Thread. But what if I cannot change Logger class? I cannot use it?
I want to clarify: I cannot use object not inherited from Stackable, Thread or Worker inside class inherited from Thread at all? It is very strange. In other languages I can.
Win 7 x64 Ultimate, php 7 32 bit with thread safety.
Related
So I have been googling and reading up and down the internet about PHP pthreads3 and how they are supposed to store data. (Or rather, how they are not)
It seems to me that the only way for a thread to store its data properly is to create a new Threaded object and send it to the thread. The thread can then use this Threaded object to store nearly any data.
My question, and biggest issue with grasping PHP threads:
Is it possible to have the thread create its own storage objects when it wants?
I have no idea how or why, since all the answer I've found on this tell a vague, elaborate and confusing "maybe, but no", mostly related to poor performance and memory issues/safety.
This seems like it should be possible, somehow:
class someFantasticThread extends Thread {
public $someData;
function run(){
while(true){
//Create a fresh storage for the new data this iteration
$this->someData = new SomeCoolStorage(); // Can this work somehow without all the issues?
$this->someData[] = 'amazingdata'; // Do something amazing and store the new results in $someData
$this->someData[] = new SomeCoolStorage(); // This would also be desireable, if it can somehow be done
//don't mind the obvious loop issues. Imagine this is a well formed loop
}
}
}
class SomeCoolStorage extends Threaded{}
// Start the thread
$threadObj = new someFantasticThread();
$threadObj->start();
while(true){
// at some point, retrieve the data and do something useful with the contained results
// doSomethingAwesome($threadObj->someData);
}
It seems to me that the only way for a thread to store its data properly is to create a new Threaded object and send it to the thread.
Yes, that is one way to do it.
Is it possible to have the thread create its own storage objects when it wants?
Yes, but only if you manipulate it within that thread (or any child threads it may spawn).
One of the fundamental things to understand when using threads in PHP is that objects of a Threaded class are tied to the context in which they are created. This means that if you create a Threaded object in the main thread, pass this object into a spawned child thread, and then join that spawned child thread, then you may continue to use that Threaded object as normal.
Example 1 (constructor injection):
<?php
$store = new Threaded(); // created in the main thread
$thread = new class($store) extends Thread {
public $store;
public function __construct(Threaded $store)
{
$this->store = $store;
}
public function run()
{
$this->store[] = 1;
$this->store[] = 2;
}
};
$thread->start() && $thread->join();
print_r($store); // continue using it in the main thread
This will output:
Threaded Object
(
[0] => 1
[1] => 2
)
In the example above, we could also have created the Threaded object inside of the constructor, and then performed a var_dump($thread->store); at the end of the script. This works because the Threaded object is still being created in the outermost scope in which it is needed, and thus it is not tied to the scope of any child threads that may have already been destroyed. (The only part of a Thread in PHP that is executed in a separate thread is the Thread::run method.)
Similar to the above example, we could also have used setter injection. (Though, again, just so long as the setter is being called by the thread in the outer most scope in which the Threaded object will be used.)
The problem that many developers who are new to threading in PHP seem to encounter, is when they create a Threaded object from inside of a new thread, and then expect to be able to use that Threaded object when they have joined that same thread.
Example:
<?php
$thread = new class() extends Thread {
public $store;
public function run()
{
$this->store = new Threaded(); // created inside of the child thread
$this->store[] = 1;
$this->store[] = 2;
}
};
$thread->start() && $thread->join();
print_r($thread->store); // attempt to use it in the outer context (the main thread)
This will output:
RuntimeException: pthreads detected an attempt to connect to an object which has already been destroyed in %s:%d
This is because the Threaded object in $thread->store has been destroyed when joining the spawned child thread. This problem can be far more subtle, too. For example, creating new arrays inside of Threaded objects will automatically cast them to Volatile objects (which are also Threaded objects).
This means that the following example will not work either:
<?php
$thread = new class() extends Thread {
public $store;
public function run()
{
$this->store = [];
$this->store[] = 1;
$this->store[] = 2;
}
};
$thread->start() && $thread->join();
print_r($thread->store);
Output:
RuntimeException: pthreads detected an attempt to connect to an object which has already been destroyed in %s:%d
To come back to your example code, what you're doing is absolutely fine, but only so long as you do not attempt to use $this->someData outside of that child thread.
Is there any way to specify what a thread should inherit when using a Pool, the same way you can in Thread:
$thread = new MyThread();
$thread->start(PTHREADS_INHERIT_INI | PTHREADS_INHERIT_CONSTANTS);
I'm looking for a way to do it with a Pool, something like:
$pool->shutdown(<options>);// doesn't work
I couldn't find any way to do it in the docs. Maybe I'm missing something.
Pool takes a Worker class in __construct:
new Pool(8, MyWorker::class);
Where MyWorker looks something like:
class MyWorker {
public function start() {
return parent::start(PTHREADS_INHERIT_INI | PTHREADS_INHERIT_CONSTANTS);
}
}
I want to implement the threading concept in CakePHP 3.0 ,
But when I try to extend the thread class, it gives an error of "Thread class not found"
I have also implemented it in core php and its working as expected,
But somehow its not working with cakephp.
Here is the corephp code
<?php
class AsyncOperation extends Thread {
public function __construct($arg) {
$this->arg = $arg;
}
public function run() {
if ($this->arg) {
$sleep = rand(1,60);
for ($i=0; $i < 100 ; $i++) {
sleep(1);
echo $this->arg."----------->".$i."<br/>";
}
}
}
}
class CallingClass {
public function runScript($var)
{
print_r("start run script");
$th = new AsyncOperation($var);
$th->start();
print_r("continue running");
}
}
$wow = new AsyncOperation("First");
$wow->start();
$wow2 = new AsyncOperation("Last");
$wow2->start();
?>
And in CakePHP 3
class AsyncOperation extends Thread
You want to learn about namespaces in php. Cake and almost every lib these days uses them. You need to use the use keyword and import the class from another namespace if it does not exist within the namespace your current class is in. Or, not really best practice, provide the absolute namespace.
Also I'm not sure what you try to do, but instead of threads I would recommend to take a look at work queues likes RabbitMQ or ZeroMQ.
Your php version doesn't have the thread class. By default, if you install it on LINUX, you won't have the thread class.
You need to download the php source code, enable the zts and then compile it.
This is how I did on linux:
Enable zts on redhat - pthreads on php
Just add simple line
use Thread;
I am trying to implement muti-threading in php using pthread to send emails. The basic idea here is to send email as a background job so that users dose not have to wait for the task to finish.
I have a service that users PHPMailer to send emails and its working fine. I am using the following code to muti thread
class ThreadWorkerService extends \Thread {
private $_runMethod;
private $_vars;
private $_autoloderPath;
function __construct($vars) {
$this->_vars = $vars;
$reflector = new \ReflectionClass('Composer\Autoload\ClassLoader');
$dir = dirname($reflector->getFileName());
$this->_autoloderPath = $dir . "/../autoload.php";
}
public function setRunMethod($method) {
$this->_runMethod = $method;
}
public function run() {
if (!class_exists('Composer\Autoload\ClassLoader')) {
if (file_exists($this->_autoloderPath )) {
require_once( $this->_autoloderPath );
} else {
echo "autoloder not found";
}
}
$method = $this->_runMethod;
$results = $method($this->_vars);
}
}
$storage = new \Threaded();
$storage['emails'] = $emailArray;
$storage['config'] = $config;
$threadWorker = new ThreadWorkerService($storage);
$threadWorker->setRunMethod(function ($vars) {
$emailArray = $vars['emails'];
$config = $vars['config'];
$emailService = new \MyServices\EmailService($config);
$emailService->sendAllEmails(true, $emailArray);
}
});
$threadWorker->start(PTHREADS_INHERIT_CONSTANTS);
The issue here is that the tread dose not execute if i don't use
$threadWorker->join();
which eliminates the whole purpose of muti-treading in this scenario, what I want to know is, if it is possible to keep the child thread alive even when the parent process is complete. I have even tried detaching the thread with no luck.
I am familiar with on how to do it with messaging services like RabbitMQ, but I want to keep the application independent.
The issue here is that the thread does not execute if I don't use: $threadWorker->join();, which eliminates the whole purpose of multi-threading in this scenario.
It is likely the case that the main thread's stdout, or some other dependency, is being closed or destroyed before the thread gets to execute.
Taken from the PHP manual for Thread:
Warning: Relying on the engine to determine when a Thread should join may cause undesirable behaviour; the programmer should be explicit, where possible.
You don't need to join immediately, but it is advisable to join explicitly.
The following example code illustrates the problem:
<?php
class Test extends Thread {
public function run() {
sleep(1);
echo "Thread\n";
}
}
$test = new Test();
$test->start();
echo "End\n";
?>
CPU speed permitting, the main context will begin to destroy the Thread before the Thread gets to echo.
You will normally get the output:
End
Thread
However, if the code is more complex, for example, code that manipulates dependencies set in the constructor of the Thread, those dependencies might have already been destroyed by the time they are used.
A last ditch attempt to join implicitly is made (in the most recent versions of pthreads), but you cannot rely on destruction order being compatible with your expectations, and so explicit join is preferable.
Noteworthy: The most recent versions of pthreads (PHP7+) prohibit execution anywhere but CLI; If this is code that is being executed at the frontend of a web server, you will need to rethink your architecture.
I have script with defined class (for instance, Singleton.php). This class implements classic singleton pattern as in PHP manual:
class Singleton {
private static $instance;
public static function getInstance()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
public function run() {
// bunch of "thread safe" operations
} }
$inst = Singleton::getInstance();
$inst->run();
Question. If I call this script twice from command line ('php Singleton.php'), will run() method be really "thread safe"? It seems that it will not. I used to imitate single-process run via text file where some flag is stored, but it seems that there might be other cases. Your thoughts?
Singletons have nothing to do with thread-safety. They are here to only have one instance of an object per process.
so, to answer your question: no, your script is not thread safe. php will start one process (not thread) for each call on the cli. both processes will create an instance of your class and both will try to write the file.
the process to later write the file will win, and overwrite changes from the first process.
PHP is not threaded - it is process oriented. Each invocation of PHP (wether it be commandline or apache instance) is memory independent.
Your singleton will only be unique to that one process.
(oh and instead of doing $c=__CLASS__; $instance = new $c; you should use 'self' like $instance = new self();. Same result, less fuss. Also be sure to set your __construct() private/protected)
If you run this script from the command line twice (concurrently, I guess), you will get two completely distinct processes, therefore the thread safety is not an issue: there are no threads here.