× 警告!旧版文档已经暂停维护,请查看新版文档。点击前往新版文档

Coroutine\Channel::select

废弃

此方法存在安全问题,已废弃

通道读写检测。类似于socket_selectstream_select可以检测channel是否可进行读写。

原型

function Coroutine\Channel::select(array &$read, array &$write, float $timeout = -1);

$read$write数组中有部分channel对象处于可读或可写状态,select会立即返回,不会产生协程调度。当数组中没有任何channel可读或可写时,将挂起当前协程,并设置定时器。当其中一个通道可读或可写时,将重新唤醒当前协程。

select操作只检测channel列表的可读或可写状态,但并不会读写channel,在select调用返回后,可遍历$read$write数组,执行poppush方法,完成通道读写操作。

参数

  • $read 数组引用类型,元素为channel对象,读操作检测,可以为null
  • $write 数组引用类型,元素为channel对象,写操作检测,可以为null
  • $timeout 浮点型,超时设置,单位为秒,最小粒度为0.001秒,即1ms。默认为0,表示永不超时。

返回值

  • 成功返回true,底层会修改$read$write数组,$read$write中的元素,即是可读或可写的channel
  • 超时或传入的参数错误,如$read$write中有非channel对象,底层返回false

注意事项

早期版本中Coroutine\Channel由于存在一些问题,在Swoole4.0.3版本重构并废弃了 Coroutine\Channel::select 方法。所以在Swoole4.0.3以上的版本请使用channel->pop($timeout)替代。

fibonacci 实例

$c1 = new chan();
$c2 = new chan();
function fibonacci($c1, $c2)
{
    go(function () use ($c1, $c2) {
        $a = 0;
        $b = 1;
        while(1) {
            $read_list = [$c2];
            $write_list = [$c1];
            $result = chan::select($read_list, $write_list, 2);
            if ($write_list) {
                $t = $a + $b;
                $a = $b;
                $b = $t;
                $c1->push($a);
            }
            if ($read_list) {
                $ret = $c2->pop();
                if ($ret === 1) {
                    return 1;
                }
            }
        }
    });
}
$num = 10;
go(function () use ($c1, $c2, $num) {
    for ($i = 0; $i < $num; $i ++) {
        $ret = $c1->pop();
        echo "fibonacci @$i $ret\n";
    }
    $c2->push(1);
});    
fibonacci($c1, $c2);

  • 落落

    斐波那契数列的案例虽然跑起来了,但其实和协程本身并没有很大的关系啊……原理更像是生成器,都是惰性求值,只不过是把生成的值暂存在通道里,取出的时候再生成下一个值。

    Go 里有一个利用无限生成过滤网协程,过滤生成无限素数(只要机器抗得住)的例子。一样的代码用 Swoole 的协程改写后,运行不了:

    2
    Segmentation fault
    

  • 落落

    ~~~php

  • 落落

    (发不了代码么)


    $primeChan = sieve(); while (true) { echo $primeChan->pop() . PHP_EOL; } function generate(): Chan { $ch = new Chan(); go(function () use ($ch) { $i = 2; while (true) { $ch->push($i); $i++; } }); return $ch; } function filter(Chan $primChan, int $filterInt): Chan { $out = new Chan(); go(function () use ($out, $primChan, $filterInt) { while (true) { $num = $primChan->pop(); if ($num % $filterInt !== 0) { $out->push($num); } } }); return $out; } function sieve(): Chan { $primeChan = new Chan(); go(function () use ($primeChan) { $base = generate(); while (true) { $filterInt = $base->pop(); $base = filter($base, $filterInt); $primeChan->push($filterInt); } }); return $primeChan; }

  • 落落

    前排提醒,Channel::select() 已经在 4.0.3 版本移除,参考链接