PHP协程内容的详解
来源:不言
发布时间:2018-12-15 15:54:29
阅读量:864
这篇文章给大家分享了关于php协成的内容,有一定的参考价值,希望可以帮助到有需要的朋友。
概念
咱们知道多进程和多线程是实现并发的有效方式。但多进程的上下文切换资源开销太大;多线程开销相比要小很多,也是现在主流的做法,但其的控制权在内核,从而使用户(程序员)失去了对代码的控制,而且线程的上下文切换也是有一定开销的。 这时为了解决以上问题,"协程"(coroutine)的概念就产生了。你可以将协程理解为更轻量级的线程。这种线程叫做“用户空间线程“。协程,有下面两个特点:
协同。因为是由程序员自己写的调度策略,其通过协作而不是抢占来进行切换
在用户态完成创建,切换和销毁
PHP对协程的支持是在迭代生成器的基础上, 增加了可以回送数据给生成器的功能(调用者发送数据给被调用的生成器函数)。 这就把生成器到调用者的单向通信转变为两者之间的双向通信。
迭代器
迭代器的概念这里就不赘述了。下面看看我们自己实现的一个迭代器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | class MyIterator implements Iterator
{
private $var = array ();
public function __construct( $array )
{
if ( is_array ( $array )) {
$this -> var = $array ;
}
}
public function rewind () {
echo "rewinding\n" ;
reset( $this -> var );
}
public function current() {
$var = current( $this -> var );
echo "current: $var\n" ;
return $var ;
}
public function key() {
$var = key( $this -> var );
echo "key: $var\n" ;
return $var ;
}
public function next() {
$var = next( $this -> var );
echo "next: $var\n" ;
return $var ;
}
public function valid() {
$var = $this ->current() !== false;
echo "valid: {$var}\n" ;
return $var ;
}
}
$values = array (1,2,3,4);
$it = new MyIterator( $values );
foreach ( $it as $a => $b ) {
print "=====\n" ;
sleep(2);
}
|
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | rewinding
current: 1
valid: 1
current: 1
key: 0
=====
next: 2
current: 2
valid: 1
current: 2
key: 1
=====
next: 3
current: 3
valid: 1
current: 3
key: 2
=====
next: 4
current: 4
valid: 1
current: 4
key: 3
=====
next:
current:
valid:
|
生成器
有了yeild的方法就是一个生成器(生成器实现了Iterator接口,即一个生成器有迭代器的特点)。生成器的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function xrange( $start , $end , $step = 1) {
for ( $i = $start ; $i <= $end ; $i += $step ) {
echo $i . "\n" ;
yield;
}
}
foreach (xrange(1, 10) as $num ) {
}
$gene = xrange(1, 10);
$gene ->current();
$gene ->next();
$gene ->current()
|
输出:
生成器各方法详解可看文档: http://php.net/manual/zh/class.generator.php
注意:
生成器不能像函数一样直接调用,调用方法如下:
1. foreach他
2. send($value)
3. current / next...
yield
yield的语法很灵活,我们用下面的例子,让大家能明白yield语法的使用。
用例1: 让出cpu执行权
1 2 3 4 5 6 7 8 9 | function task1 () {
for ( $i = 1; $i <= 10; ++ $i ) {
echo "This is task 1 iteration $i.\n" ;
yield;
}
}
$a = task1();
$a ->current();
$a ->send(1);
|
输出:
1 2 | This is task 1 iteration 1.
This is task 1 iteration 2.
|
用例2: yield的返回
1 2 3 4 5 6 7 8 9 10 11 12 13 | function task2 () {
for ( $i = 1; $i <= 10; ++ $i ) {
echo "This is task 2 iteration $i.\n" ;
yield "lm$i" ;
}
}
$a = task2();
$res = $a ->current();
var_dump( $res );
$res = $a ->send(1);
var_dump( $res );
|
输出:
1 2 3 4 | This is task 2 iteration 1.
string(3) "lm1"
This is task 2 iteration 2.
string(3) "lm2"
|
用例3: yield接收值
1 2 3 4 5 6 7 8 9 10 | function task3 () {
for ( $i = 1; $i <= 10; ++ $i ) {
echo "This is task 3 iteration $i.\n" ;
$getValue = yield;
echo $getValue . " " ;
}
}
$a = task3();
$a ->current();
$a ->send( "aa" );
|
输出:
1 2 | This is task 3 iteration 1.
aa This is task 3 iteration 2.
|
用例4: yeild接收和返回写在一起
1 2 3 4 5 6 7 8 9 10 11 | function task4 () {
for ( $i = 1; $i <= 10; ++ $i ) {
echo "This is task 4 iteration $i.\n" ;
$ret = yield "lm$i" ;
echo $ret ;
}
}
$a = task4();
var_dump( $a ->current());
var_dump( $a ->send( "hhh " ));
var_dump( $a ->send( "www " ));
|
输出:
1 2 3 4 5 6 | This is task 4 iteration 1.
string(3) "lm1" hhh
This is task 4 iteration 2.
string(3) "lm2" www
This is task 4 iteration 3.
string(3) "lm3"
|