PHP多线程和向父线程返回值
我已经做了一个多小时了,我已经阅读了所有关于PHP中多线程的文章,当涉及到将值返回到父线程时,我就不知所措了。实际上,我一直在强制使用各种不同的方法组合,将变量传递回父线程,但没有成功。我甚至不确定在这一点上是否可能 我尝试过使用返回、回调、匿名方法、调用的静态类/方法/变量,但什么都不起作用,当代码完成执行时,我继续得到一个空数组 尝试1)我创建了一个名为Results的类,使用一个静态方法为静态变量数组赋值,使用另一个静态方法在代码执行完毕时返回所有数据,但打印显示数据被添加到静态变量数组,脚本执行完毕后,静态processData方法返回一个空数组 尝试2)我从Results类中删除了静态元素,并将其放置在TaskManager中,使用匿名方法作为回调,我能够将值返回给TaskManager,但代码执行完毕后,再次返回一个空数组 尝试3)我创建了一个全局匿名方法用作回调,同样,值被传递给回调方法,但您猜到了,代码执行完成时为空数组 我列举了三次尝试,但实际上,这更像是20次尝试;我束手无策,非常感谢您的帮助 这是我一直在使用的代码PHP多线程和向父线程返回值,php,multithreading,Php,Multithreading,我已经做了一个多小时了,我已经阅读了所有关于PHP中多线程的文章,当涉及到将值返回到父线程时,我就不知所措了。实际上,我一直在强制使用各种不同的方法组合,将变量传递回父线程,但没有成功。我甚至不确定在这一点上是否可能 我尝试过使用返回、回调、匿名方法、调用的静态类/方法/变量,但什么都不起作用,当代码完成执行时,我继续得到一个空数组 尝试1)我创建了一个名为Results的类,使用一个静态方法为静态变量数组赋值,使用另一个静态方法在代码执行完毕时返回所有数据,但打印显示数据被添加到静态变量数组,
<?php
/**
* author : Marc Quinton / April 2008.
*
* a simple task management framework using pcntl_fork, pcntl_wait.
*
* - see at bottom for a sample usage.
* - you shoud overring Task class (SleepingClass is an example), and manage them in a pool, using taskManager
*/
error_reporting(E_ALL);
class Results {
var $datas = array();
public function data($data)
{
$this->datas[] = $data;
}
public function processResults()
{
foreach($this->datas as $data)
{
print_r($data);
}
}
}
class Task {
protected $data;
protected $pid;
protected $ppid;
function __construct(){
}
function fork(){
$pid = pcntl_fork();
if ($pid == -1)
throw new Exception ('fork error on Task object');
elseif ($pid) {
# we are in parent class
$this->pid = $pid;
# echo "< in parent with pid {$his->pid}\n";
} else{
# we are is child
$this->run();
}
}
function run(){
# echo "> in child {$this->pid}\n";
# sleep(rand(1,3));
$this->ppid = posix_getppid();
$this->pid = posix_getpid();
}
# call when a task in finished (in parent)
function finish(){
echo "task finished {$this->pid}\n";
}
function pid(){
return $this->pid;
}
}
class SleepingTask extends Task{
public $mybl;
public $data;
public $cback;
function __construct($bl, $cb){
$this->cback = $cb;
$this->mybl = $bl;
}
function run(){
global $callback;
parent::run();
echo "My BL ID: " . $this->mybl . " /END BL ID\n";
$callback(array('whoa' => $this->mybl));
sleep(rand(1,2));
exit(0);
}
}
class TaskManager{
protected $pool;
protected $datas = array();
function __construct(){
$this->pool = array();
}
function add_task($task){
$this->pool[] = $task;
}
function run(){
foreach($this->pool as $task){
$task->fork();
}
# print_r($this);
# sleep(60);
while(1){
echo "waiting\n";
$pid = pcntl_wait($extra);
if($pid == -1)
break;
echo ": task done : $pid\n";
$this->finish_task($pid);
}
echo "processes done ; exiting\n";
}
function finish_task($pid){
if($task = $this->pid_to_task($pid)) {
$task->finish();
}
}
function pid_to_task($pid){
foreach($this->pool as $task){
if($task->pid() == $pid)
return $task;
}
return false;
}
}
$datas = array();
$callback = function ($data) {
print_r($data);
global $datas;
$datas[] = $data;
};
$manager = new TaskManager();
for($i=0 ; $i<10 ; $i++)
$manager->add_task(new SleepingTask($i, $callback));
$manager->run();
print_r($datas);
exit(0);
?>
我已经运行了您的代码,每次都成功调用了您的回调。但是,值得记住的是,这是多进程的,而不是多线程的。这意味着,对于添加到阵列中的每个项目,全局阵列在每个场合都是全新的,因此,当您添加新项目时,在每次推送之后,其中只有一个项目 此外,这些添加中的每一个都发生在子进程中,因此当控制权恢复到父进程时,全局数组也是新的,因此正确地说,其中没有任何内容 这里有几个解决方案:
- 使用数据库获取结果
- 使用其他一些共享存储机制,例如归档系统或Memcache
- 使用进程间通信系统,例如。我没有使用过它,但它可能很有趣-理想情况下,您希望将消息发送到特定的PID(父任务)
就我个人而言,我会使用数据库,因为这是一种方便的检索机制。我建议看一下socket\u create\u pair() 在PHP手册中,有一个关于fork()父进程和子进程之间的进程间通信(IPC)的非常简单的例子
使用serialize()和unserialize()甚至可以传输复杂的数据类型,比如数组…我不知道它是否相关,但是
额外的在任务管理器::run()
@halfer中没有定义,这是可以的。@Havenard,很好的地方。尽管如此,我的IDE还是会抱怨,我个人还是会在调用之前将其设置为null。这里的问题是您不能在父进程和子进程之间共享数据。它们是不同的,不能看到彼此的数据或结构。如果这些是线程,您可以同步/加入它们。这就是为什么PHPs对你可能有用的原因。如果您想在N个进程之间共享数据,您需要为它们实现一种通信机制——共享内存、它们通过获取锁、数据库或类似内容访问的文件。或者简单地使用实际线程。