前言
第一部分: 半协程调度器
- 统一生成器接口
- 生成器迭代
- 生成器返回值
- 生成器委托
- 改写 return
- 抽象异步模型
- 引入异常处理
- 异常: 嵌套任务透传
- 异常: 传递流程
- 异常: 重新进行 CPS 变换
- 异常: 重新加入 Async
- Syscall 与 Context
- 调度器: 里程碑
- spawn
- callcc
- race 与 timeout
- all 与 parallel
- channel 与协程间通信
- 无缓存 channel
- 缓存 channel
- channel 演示
- FutureTask 与 fork
第二部分: Koa
- 穿越地心之旅
- 洋葱圈模型
- rightReduce与中间件compose
- Koa::Application
- Koa::Context
- Koa::Request
- Koa::Response
- Koa - HelloWorld
- Middleware Interface
- Middleware: 全局异常处理
- Middleware: Router
- Middleware: 请求超时
- 一个综合示例
附录
参考
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
Syscall 与 Context
Syscall
与Context
按照nikic的思路引入与调度器内部交互的Syscall
,将需要执行的函数打包成Syscall
,通过yield返回迭代器,可以从Syscall
参数获取到当前迭代器对象,这里提供了一个外界与AsyncTask交互的扩展点。
我们借此演示如何添加跨生成器上下文,在嵌套生成器共享数据,解耦生成器之间依赖。
<?php
final class AsyncTask implements Async
{
public $gen;
public $continuation;
public $parent;
// 我们在构造器添加$parent参数, 把父子生成器链接起来,使其可以进行回溯
public function __construct(\Generator $gen, AsyncTask $parent = null)
{
$this->gen = new Gen($gen);
$this->parent = $parent;
}
public function begin(callable $continuation)
{
$this->continuation = $continuation;
$this->next();
}
public function next($result = null, $ex = null)
{
try {
if ($ex) {
$value = $this->gen->throw_($ex);
} else {
$value = $this->gen->send($result);
}
if ($this->gen->valid()) {
// 这里注意优先级, Syscall 可能返回\Generator 或者 Async
if ($value instanceof Syscall) { // Syscall 签名见下方
$value = $value($this);
}
if ($value instanceof \Generator) {
$value = new self($value, $this);
}
if ($value instanceof Async) {
$cc = [$this, "next"];
$value->begin($cc);
} else {
$this->next($value, null);
}
} else {
$cc = $this->continuation;
$cc($result, null);
}
} catch (\Exception $ex) {
if ($this->gen->valid()) {
$this->next(null, $ex);
} else {
$cc = $this->continuation;
$cc($result, $ex);
}
}
}
}
Syscall将 (callable :: AsyncTask $task -> mixed) 包装成单独类型:
<?php
class Syscall
{
private $fun;
public function __construct(callable $fun)
{
$this->fun = $fun;
}
public function __invoke(AsyncTask $task)
{
$cb = $this->fun;
return $cb($task);
}
}
因为PHP对象属性为Hashtable实现,而生成器对象本身无任何属性,我们这里把Context
的KV数据附加到根生成器对象上,然后得到的Context的Get与Set函数:
<?php
function getCtx($key, $default = null)
{
return new Syscall(function(AsyncTask $task) use($key, $default) {
while($task->parent && $task = $task->parent);
if (isset($task->gen->generator->$key)) {
return $task->gen->generator->$key;
} else {
return $default;
}
});
}
function setCtx($key, $val)
{
return new Syscall(function(AsyncTask $task) use($key, $val) {
while($task->parent && $task = $task->parent);
$task->gen->generator->$key = $val;
});
}
<?php
function setTask()
{
yield setCtx("foo", "bar");
}
function ctxTest()
{
yield setTask();
$foo = (yield getCtx("foo"));
echo $foo;
}
$task = new AsyncTask(ctxTest());
$task->begin($trace); // output: bar
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论