Swoole-src: coroutine::list 遍历当前进程中正在运行的协程总是多一个

Created on 21 Feb 2020  ·  3Comments  ·  Source: swoole/swoole-src

<?php

use  \Swoole\Coroutine;
use  \Swoole\Coroutine\WaitGroup;
use  \Swoole\Coroutine\Channel;

Coroutine::create(function() {

    $wg=new  WaitGroup();

    $wg->add(1);
    //  第一次打印CoroutineList, 会输出主协程ID(=1)
    foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID:".$Cid);
    }

    Coroutine::create(function()  use($wg) {
        $Cid=Coroutine::getCid();
        var_dump("A.新启动协程ID".$Cid);
        Coroutine::sleep(2);
        $wg->done();

    });

    $wg->wait();  //  等待A协程运行结束

        foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID: ".$Cid);   //  这里遍历的时候A协程(ID=2)为什么会被遍历出来?
    }

    $wg->add(1);
    Coroutine::create(function()  use($wg) {
        $Cid=Coroutine::getCid();
        var_dump("B.新启动协程ID".$Cid);
        Coroutine::sleep(2);
        $wg->done();

    }); 
    $wg->wait();  //  等待B协程运行结束

        foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID: ".$Cid); //  这里遍历的时候B协程(ID=3)为什么会被遍历出来?
    }

});

运行以上代码,结果:

string(34) "进程中正在运行的协程ID:1"
string(20) "A.新启动协程ID2"

string(35) "进程中正在运行的协程ID: 2"   //  这里$wg->wait()  等待 A协程(ID=2)结束,才遍历状态,为什么A协程会出现在list列表?

string(35) "进程中正在运行的协程ID: 1"
string(20) "B.新启动协程ID3"

string(35) "进程中正在运行的协程ID: 3"  //  这里$wg->wait()  等待 B协程结束,才遍历状态,为什么B协程(ID=3)会出现在list列表?
string(35) "进程中正在运行的协程ID: 1"

question

Most helpful comment

@qifengzhang007
$wg->done();会发生一次协程的调度,你可以打印跟踪一下。我这里有一份符合你预期的代码:

<?php

use  \Swoole\Coroutine;
use  \Swoole\Coroutine\WaitGroup;
use  \Swoole\Coroutine\Channel;

use function Co\run;

Coroutine::create(function() {

    $wg = new WaitGroup();

    $wg->add(1);
    //  第一次打印CoroutineList, 会输出主协程ID(=1)
    foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID:".$Cid);
    }

    Coroutine::create(function()  use($wg) {
        $Cid=Coroutine::getCid();
        var_dump("A.新启动协程ID".$Cid);
        Coroutine::sleep(2);
        var_dump("1");
        $wg->done();
        var_dump("2");
    });

    var_dump("3");
    $wg->wait();  //  等待A协程运行结束
    var_dump("4");
    Coroutine::sleep(0.1);

    foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID: ".$Cid);   //  这里遍历的时候A协程(ID=2)为什么会被遍历出来?
    }

    $wg->add(1);
    Coroutine::create(function()  use($wg) {
        $Cid=Coroutine::getCid();
        var_dump("B.新启动协程ID".$Cid);
        Coroutine::sleep(2);
        $wg->done();
    }); 
    $wg->wait();  //  等待B协程运行结束

    Coroutine::sleep(0.1);

    foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID: ".$Cid); //  这里遍历的时候B协程(ID=3)为什么会被遍历出来?
    }
});

All 3 comments

@qifengzhang007
$wg->done();会发生一次协程的调度,你可以打印跟踪一下。我这里有一份符合你预期的代码:

<?php

use  \Swoole\Coroutine;
use  \Swoole\Coroutine\WaitGroup;
use  \Swoole\Coroutine\Channel;

use function Co\run;

Coroutine::create(function() {

    $wg = new WaitGroup();

    $wg->add(1);
    //  第一次打印CoroutineList, 会输出主协程ID(=1)
    foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID:".$Cid);
    }

    Coroutine::create(function()  use($wg) {
        $Cid=Coroutine::getCid();
        var_dump("A.新启动协程ID".$Cid);
        Coroutine::sleep(2);
        var_dump("1");
        $wg->done();
        var_dump("2");
    });

    var_dump("3");
    $wg->wait();  //  等待A协程运行结束
    var_dump("4");
    Coroutine::sleep(0.1);

    foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID: ".$Cid);   //  这里遍历的时候A协程(ID=2)为什么会被遍历出来?
    }

    $wg->add(1);
    Coroutine::create(function()  use($wg) {
        $Cid=Coroutine::getCid();
        var_dump("B.新启动协程ID".$Cid);
        Coroutine::sleep(2);
        $wg->done();
    }); 
    $wg->wait();  //  等待B协程运行结束

    Coroutine::sleep(0.1);

    foreach(Coroutine::list()  as $key=>$Cid){
        var_dump("进程中正在运行的协程ID: ".$Cid); //  这里遍历的时候B协程(ID=3)为什么会被遍历出来?
    }
});

你可以通过getBackTrace来看到B协程仍处于$wg->done那一行, 当你的主协程结束后才会重新返回到B协程并释放它

@huanghantao @twose
非常感谢两位,果然是大神。
尤其是@huanghantao 使用代码示例的方式,通过本人运行对比结果,彻底理解了这个过程。

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andreybolonin picture andreybolonin  ·  4Comments

sagesan picture sagesan  ·  4Comments

nick-zh picture nick-zh  ·  3Comments

Gemorroj picture Gemorroj  ·  3Comments

godtail picture godtail  ·  4Comments