我已经在这里工作了一个多小时,我已经阅读了关于PHP中多线程的所有内容,当涉及到将值返回到父线程时,我迷失了。我实际上已经粗暴地强制使用不同的方法组合,以便将变量传递回父线程,但没有成功。我甚至不确定此时是否可能。
我已经尝试了带有返回,回调,匿名方法,调用的静态类/方法/变量,并且没有任何工作,我在代码完成执行时继续得到一个空数组。
尝试1)我创建了一个名为Results的类,其中一个静态方法为静态var数组赋值,另一个静态方法在代码执行完毕后返回所有数据,print_r显示数据为但是,当脚本完成执行静态processData方法时,返回一个空数组。
尝试2)我从Results类中删除了静态元素,并将它放在TaskManager中,使用匿名方法作为回调,我能够将值返回给TaskManager,但是,当代码完成执行时,一个空数组。
尝试3)我创建了一个全局匿名方法用作回调,同样,值被传递给回调方法,但是你猜对了,代码执行完毕后是空数组。
我列出了三次尝试,但实际上,它更像是20次尝试;我在我的智慧结束,任何帮助都非常感谢。
以下是我一直在使用的代码。
<?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);
?>
答案 0 :(得分:3)
我运行了你的代码,每次都成功调用你的回调。但是,值得注意的是,这是多过程,而不是多线程。这意味着对于添加到数组中的每个项目,全局数组在每种情况下都是全新的,因此当您添加新项目时,每次推送后只有一个项目。
此外,每个添加都发生在子进程中,因此当控制恢复到父进程时,全局数组也是新的,因此其中没有正确的内容。
这里有一些解决方案:
就个人而言,我会使用数据库,因为无论如何这都是一种方便的机制来检索它。
答案 1 :(得分:0)
我建议看一下 socket_create_pair()。
在PHP手册中是一个很短的&amp; fork() - 父级和子级之间的进程间通信(IPC)的简单示例。
使用序列化()和反序列化()您甚至可以传输复杂的数据类型,例如数组......