谈谈 PHP 协程的任务调度技术
其实 PHP 的 yield 是做死的节奏。因为像我之前一篇文章提到的 PHP 的 ArrayAccess 一样,不懂或不知道它并不会影响一个程序员的开发与设计。
也许他们实现 yield,只是为了实现而实现,其他语言有的东西 PHP 当然得有,就这么一个理由比较有说服力。
关于 yield 在 PHP 程序里面的作用和好处是什么?我个人能想到的就是,比如一个傻逼写了一堆脚本,如果要维护这堆脚本怎么办,于是他们想到了一个好的办法,把每个脚本的代码用 function 包裹起来,在循环里面加上 yield,然后写一个最简单的任务调度管理。于是这样看似就搞定了这些恶劣的代码,几乎不用做什么修改,这样其实是很偷懒的做法,他们借助了语言级别的能力来管理这些垃圾代码,只会使得垃圾代码越来越难维护。
帮助理解 yield 的测试代码:
$ php -r 'yield;'; PHP Fatal error: The "yield" expression can only be used inside a function in Command line code on line 1 [ 2017-08-09T00:05:13+08:00 ] /, LMLPHP Fatal Error:The "yield" expression can only be used inside a function in line 6
可以看出,yield 只能包裹在 function 中。yield 不同于线程和进程,它是编译器实现的执行控制,而后者是操作系统层面的时间片控制。说的更直白一点,yield 就是高级的 goto 语句,并且还可以进行简单的双向通信。
看如下最简单的任务调度控制:
$coroutineArr = array(); require DEFAULT_THEME_PATH.'index/script/task_1.php'; require DEFAULT_THEME_PATH.'index/script/task_2.php'; $coroutineArr[] = task_1(); $coroutineArr[] = task_2(); $firstTime = true; for(;;){ foreach ($coroutineArr as $k => $v) { if ($firstTime) { $v->current(); } else { $v->next(); } } $firstTime = false; }
yield 中断返回 generator 对象,该对象一迭代默认会执行 rewind 方法,所以加上了第一次的判断,以免第一次没有执行。另外的 send 方法效果其实和 next 一样,唯一的不同就是可以发送数据。
yield 的作用其实只是中断,类似于 goto 语句,这样的代码导致阅读理解起来非常费力,而任务调度是我唯一能想到的 yield 的作用,方便管理垃圾代码。其实仔细一想,yield 能做的所有的事情,不使用 yield 照样可以相同效果的完成。学面向对象是为什么,支持面向对象是为什么,就是为了方便管理复杂的代码控制流程。像上面的任务调度,使用观察者模式一样可以同等效果的完成,也许稍微麻烦一点点,但性能应该比 yield 要好。