PHP process: go + Chan + defer

Time:2020-2-24

Swoole4byPHPLanguage provides powerfulCSPCo programming mode. The bottom layer provides3Key words, can easily achieve all kinds of functions.

  • Swoole4ProvidedPHP AssociationGrammar fromGolangIn this directionGODevelopment team Tribute
  • PHP+SwooleThe process can work withGolangWell complemented.GolangStatic language, rigorous and powerful, with good performance,PHP+Swoole: dynamic language, flexible and easy to use

This article is based onSwoole-4.2.9andPHP-7.2.9Edition

Key word

  • go: create a process
  • chan: create a channel
  • defer: delay task, execute when the process exits, first in and then out

this3The underlying implementation of each function isMemory operation, noIOResource consumption. Just likePHPOfArrayThe same is very cheap. It can be used directly if necessary. This andsocketandfileThe latter needs to apply for port and file descriptors from the operating system, which may cause blocking in reading and writingIOWait.

Association concurrent

UsegoFunction allows a function to execute concurrently. During programming, if a piece of logic can be executed concurrently, it can be placed in thegoIn the process of cooperation.

Sequential execution

function test1() 
{
    sleep(1);
    echo "b";
}
    
function test2() 
{
    sleep(2);
    echo "c";
}

test1();
test2();

Execution result:

[email protected]:~$ time php b1.php
bc
real    0m3.080s
user    0m0.016s
sys     0m0.063s
[email protected]:~$

In the above code,test1andtest2It will be executed in sequence and needs to be3Seconds to complete.

Concurrent execution

UsegoCreate a process that allowstest1andtest2The two functions become concurrent.

Swoole\Runtime::enableCoroutine();

go(function () 
{
    sleep(1);
    echo "b";
});
    
go(function () 
{
    sleep(2);
    echo "c";
});

Swoole\Runtime::enableCoroutine()The effect is toPHPProvidedstreamsleeppdomysqliredisSwitch from synchronous block to asynchronous of cooperationIO

Execution result:

[email protected]:~$ time php co.php
bc
real    0m2.076s
user    0m0.000s
sys     0m0.078s
[email protected]:~$

You can see that it’s only used here2Seconds to complete.

  • Sequential execution time is equal to the total execution time of all tasks:t1+t2+t3...
  • Concurrent execution time is equal to the maximum execution time of all tasks:max(t1, t2, t3, ...)

Cooperative communication

Yes.goAfter keywords, concurrent programming is much easier. At the same time, it brings new problems, if any2Two processes are executed concurrently. Another process needs to rely on the execution results of the two processes. What if we solve this problem?

The answer is to use channels(Channel) inSwoole4Used in cooperationnew chanYou can create a channel. A channel can be understood as a queue with its own schedule. It has two interfacespushandpop

  • push: write content to the channel. If it is full, it will enter the waiting state and recover automatically when there is space
  • pop: read the content from the channel. If it is empty, it will enter the waiting state and recover automatically when there is data

It can be easily realized by using channelsConcurrent management

$chan = new chan(2);

1
go (function () use ($chan) {
    $result = [];
    for ($i = 0; $i < 2; $i++)
    {
        $result += $chan->pop();
    }
    var_dump($result);
});

2
go(function () use ($chan) {
   $cli = new Swoole\Coroutine\Http\Client('www.qq.com', 80);
       $cli->set(['timeout' => 10]);
       $cli->setHeaders([
       'Host' => "www.qq.com",
       "User-Agent" => 'Chrome/49.0.2587.3',
       'Accept' => 'text/html,application/xhtml+xml,application/xml',
       'Accept-Encoding' => 'gzip',
   ]);
   $ret = $cli->get('/');
   //$cli - > body response content is too large, here use HTTP status code as test
   $chan->push(['www.qq.com' => $cli->statusCode]);
});

3
go(function () use ($chan) {
   $cli = new Swoole\Coroutine\Http\Client('www.163.com', 80);
   $cli->set(['timeout' => 10]);
   $cli->setHeaders([
       'Host' => "www.163.com",
       "User-Agent" => 'Chrome/49.0.2587.3',
       'Accept' => 'text/html,application/xhtml+xml,application/xml',
       'Accept-Encoding' => 'gzip',
   ]);
   $ret = $cli->get('/');
   //$cli - > body response content is too large, here use HTTP status code as test
   $chan->push(['www.163.com' => $cli->statusCode]);
});

Execution result:

[email protected]EFQI:~/swoole-src/examples/5.0$ time php co2.php
array(2) {
  ["www.qq.com"]=>
  int(302)
  ["www.163.com"]=>
  int(200)
}

real    0m0.268s
user    0m0.016s
sys     0m0.109s
[email protected]:~/swoole-src/examples/5.0$

Use heregoCreated3Individual process2Peace association3Separate requestsqq.comand163.comHome page. Association1Need to getHttpThe result of the request. It’s used herechanTo achieve concurrent management.

  • Association1Cycle the channel twicepop, because the queue is empty, it will enter the waiting state
  • Association2Peace association3When the execution is complete, thepushData, process1Get the results, keep going down

Delayed task

In the process of CO programming, some tasks may need to be performed automatically when the co program exits to do the cleaning work. Be similar toPHPOfregister_shutdown_functionInSwoole4Can be used indeferRealization.

Swoole\Runtime::enableCoroutine();

go(function () {
    echo "a";
    defer(function () {
        echo "~a";
    });
    echo "b";
    defer(function () {
        echo "~b";
    });
    sleep(1);
    echo "c";
});

Execution result:

[email protected]:~/swoole-src/examples/5.0$ time php defer.php
abc~b~a
real    0m1.068s
user    0m0.016s
sys     0m0.047s
[email protected]:~/swoole-src/examples/5.0$

epilogue

Swoole4ProvidedGo + Chan + DeferbyPHPBrought a newCSPConcurrent programming mode. Flexible useSwoole4The features provided can solve the design and development of various complex functions in the work.