Skip to content

Commit

Permalink
updated:
Browse files Browse the repository at this point in the history
1. Runtime::child()现在返回RuntimeID;
2. Runtime::child()增加参数$id,并实现子Runtime的替换功能;
3. 增加Runtime::listen()非阻塞监听;
4. 调整Runtime::listen()、Runtime::wait()中回调函数的参数;
5. 完善测试用例及文档
  • Loading branch information
chaz6chez committed Sep 21, 2022
1 parent 980e83f commit 291972c
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 11 deletions.
70 changes: 65 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ $p->wait(function(\WorkBunny\Process\Runtime $parent, int $status){

| 方法名 | 作用范围 | 是否产生分叉 | 描述 |
|:-------------:|:-------------:|:------:|:---------------------------------------:|
| child() | parentContext || 分叉一个子Runtime |
| child() | parentContext || 分叉一个子Runtime / 替换一个子Runtime |
| run() | parentContext || 快速分叉N个子Runtime |
| wait() | parentContext | × | 监听所有子Runtime状态 |
| parent() | parentContext | × | 为父Runtime增加回调响应 |
Expand Down Expand Up @@ -136,7 +136,6 @@ $p->child(function(\WorkBunny\Process\Runtime $runtime){
});

var_dump('parent'); # 打印两次

```

```php
Expand All @@ -150,11 +149,49 @@ $p->run(function (\WorkBunny\Process\Runtime $runtime){
var_dump('parent'); # 打印5次
```

- **child()** 函数可以进行替换子Runtime行为

```php
$p = new \WorkBunny\Process\Runtime();

// 创建一个子Runtime
// 假设父RuntimeID === 0,子RuntimeID === 1
// 假设父RuntimePID === 99,子RuntimePID === 100
$id = $p->child(function(\WorkBunny\Process\Runtime $runtime){
$runtime->getId(); // 假设 id === 1
$runtime->getPid(); // 假设 pid === 100
});

if($p->isChild()){
$id === 0; // $id 在子Runtime的上下文中始终为0
posix_getpid() === 100;
}else{
$id === 1;// $id 在当前父Runtime的上下文中为1
posix_getpid() === 99;
}

// 对id === 1的子Runtime进行替换
// 该用法会杀死原id下的子Runtime并新建Runtime替换它
// 该方法并不会改变子Runtime的id,仅改变id对应的pid
$newId = $p->child(function(\WorkBunny\Process\Runtime $runtime){
$runtime->getId(); # id === 1
}, 0, $id);

if($p->isChild()){
$id === $newId === 0;
posix_getpid() !== 100; // 子Runtime PID发生变化,不再是100
// 原PID === 100的子Runtime被kill
}else{
$id === $newId === 1; // $id 没有发生变化
posix_getpid() === 99;
}
```

- 如需在子Runtime中进行 **fork** 操作,请创建新的Runtime;**不建议过多调用,因为进程的开销远比线程大**

```php
$p = new \WorkBunny\Process\Runtime();
$p->child(function(\WorkBunny\Process\Runtime $runtime){
$id = $p->child(function(\WorkBunny\Process\Runtime $runtime){
var_dump($runtime->getId()); # id !== 0
var_dump('old-child');

Expand Down Expand Up @@ -284,9 +321,32 @@ var_dump($p->getPid()); # 所有Runtime会输出

```php
$p = new \WorkBunny\Process\Runtime();
$p->wait(function(\WorkBunny\Process\Runtime $runtime, $status){

// $id RuntimeID
// $pid 进程PID
// $status 进程退出状态
$p->wait(function($id, $pid, $status){
# 子Runtime正常退出时
}, function($id, $pid, $status){
# 子Runtime异常退出时
});
```

- 非阻塞监听

**注:该方法仅父Runtime生效**

**注:该方法应配合event-loop的timer或者future进行监听**

```php
$p = new \WorkBunny\Process\Runtime();

// $id RuntimeID
// $pid 进程PID
// $status 进程退出状态
$p->listen(function($id, $pid, $status){
# 子Runtime正常退出时
}, function(\WorkBunny\Process\Runtime $runtime, $status){
}, function($id, $pid, $status){
# 子Runtime异常退出时
});
```
Expand Down
49 changes: 43 additions & 6 deletions src/Runtime.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ public function run(Closure $childContext, ?Closure $parentContext = null, int $
}

/**
* 父Runtime 监听
* @param Closure|null $success = function(Runtime, status){}
* @param Closure|null $error = function(Runtime, status){}
* 父Runtime 阻塞监听
* @param Closure|null $success = function(id, pid, status){}
* @param Closure|null $error = function(id, pid, status){}
* @param bool $exitChild 是否结束子runtime
* @return void
*/
Expand All @@ -208,6 +208,36 @@ public function wait(?Closure $success = null, ?Closure $error = null, bool $exi
}
}

/**
* 父Runtime 非阻塞监听
* @param Closure|null $success = function(id, pid, status){}
* @param Closure|null $error = function(id, pid, status){}
* @param bool $exitChild 是否结束子runtime
* @return void
*/
public function listen(?Closure $success = null, ?Closure $error = null, bool $exitChild = false): void
{
if(!$this->isChild()){
foreach ($this->_pidMap as $id => $pid){
$pid = pcntl_waitpid($pid, $status, WNOHANG);
if($pid > 0){
if ($status !== 0) {
if ($error){
$error($id, $pid, $status);
}
}else{
if($success){
$success($id, $pid, $status);
}
}
}
}
}
if($exitChild){
$this->exitChildren();
}
}

/**
* 父Runtime执行
* @param Closure|null $context = function(Runtime){}
Expand All @@ -224,11 +254,13 @@ public function parent(?Closure $context = null): void
* 创建一个子Runtime
* @param Closure|null $context = function(Runtime){}
* @param int $priority 默认 父子Runtime同为0,但父Runtime始终为0
* @return void
* @param int|null $id 该id的子Runtime如果存在则会创建新Runtime替换旧Runtime
* @return int
*/
public function child(?Closure $context = null, int $priority = 0): void
public function child(?Closure $context = null, int $priority = 0, ?int $id = null): int
{
if($id = $this->number()){
// 创建子Runtime
if($id = ($id !== null) ? $id : $this->number()){
// gc
if(isset($this->getConfig()['pre_gc']) and boolval($this->getConfig()['pre_gc'])){
gc_collect_cycles();
Expand All @@ -247,6 +279,10 @@ public function child(?Closure $context = null, int $priority = 0): void
? (int)($this->getConfig()['priority'][0])
: 0
);
// 杀死旧Runtime
if($oldPid = ($this->_pidMap[$id] ?? null)){
posix_kill($oldPid, SIGKILL);
}
$this->_pidMap[$id] = $pid;
break;
// 子Runtime
Expand All @@ -272,6 +308,7 @@ public function child(?Closure $context = null, int $priority = 0): void
$this->exit(250, $throwable->getMessage());
}
}
return $id;
}

/**
Expand Down
68 changes: 68 additions & 0 deletions tests/ChildTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,74 @@ public function testChild()
$this->assertEqualsAndRmCache('test',$this->read($file), $file);
}

/**
* 测试child的替换
* @covers \WorkBunny\Process\Runtime::child
* @covers \WorkBunny\Process\Runtime::exit
* @return void
*/
public function testChildReplace()
{
$oldId = $this->runtime()->child(function (Runtime $runtime){});

$oldPid = null;
$this->runtime()->parent(function(Runtime $runtime) use ($oldId, &$oldPid){
$oldPid = $runtime->getPidMap()[$oldId];
});

$newId = $this->runtime()->child(
function (Runtime $runtime){},
0,
$oldId
);

$newPid = null;
$this->runtime()->parent(function(Runtime $runtime) use ($newId, &$newPid){
$newPid = $runtime->getPidMap()[$newId];
});

$this->runtime()->wait(null, null, true);

$this->assertEquals(true, $oldId === $newId);
$this->assertEquals(true, $oldPid !== $newPid);
}

/**
* 测试child的替换
* @covers \WorkBunny\Process\Runtime::child
* @covers \WorkBunny\Process\Runtime::exit
* @return void
*/
public function testChildReplaceUseExit()
{
$oldId = $this->runtime()->child(function (Runtime $runtime) {
$runtime->exit();
});

$oldPid = null;
$this->runtime()->parent(function(Runtime $runtime) use ($oldId, &$oldPid){
$oldPid = $runtime->getPidMap()[$oldId];
});

$newId = $this->runtime()->child(
function (Runtime $runtime){
$runtime->exit();
},
0,
$oldId
);

$newPid = null;
$this->runtime()->parent(function(Runtime $runtime) use ($newId, &$newPid){
$newPid = $runtime->getPidMap()[$newId];
});

$this->runtime()->wait(null, null, true);

$this->assertEquals(true, $oldId === $newId);
$this->assertEquals(true, $oldPid !== $newPid);
}

/**
* 每个child只输出一次
* @return void
Expand Down

0 comments on commit 291972c

Please sign in to comment.