问题
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);
}
回答1:
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.
回答2:
Don't use PHP threads. They are essentially useless, and here is why:
First: Threads can only be used in the PHP CLI, for standalone command-line scripts. They cannot be used in PHP web applications. In web applications, concurrency is gained by allowing multiple requests to run at once. (This happens naturally in a web server environment.)
Second: Using threads requires extensive, explicit support in all parts of your application. Classes which do not extend Threaded cannot be used in threaded applications -- this makes most PHP classes and frameworks unavailable. In fact, even some built-in PHP classes cannot be used safely in threaded code.
The long and the short of the matter is: the PHP pthreads extension is a half-hearted attempt to introduce threading to a language which was never designed to support it. The extension is heavily limited, awkward to use, and slow. Avoid it.
来源:https://stackoverflow.com/questions/44769481/how-should-a-php-thread-store-its-data