In the days when yield and Xie cheng of PHP filled in the pit were together (2)

  coroutine, Parallel, php, yield

First of all, this is the first time I have copied and pasted the public number article to sf.gg.

Secondly, a long time ago, I dug a hole in yield and filled it myself, otherwise I would bury myself sooner or later.

Finally, if you want to see the previous pit, please send “yield” to the public number at the end of the article. I have opened the automatic reply function of Gao dashang, which is extremely rare!

PS: At the end of the article, I made a mistake and got a conclusion by mistake: send cannot be used in foreach and I guess this is a PHP bug. Actually, it is not. The real reason is rough and simple understanding that send will make the generator continue to execute it once. This matter tells us:

In addition to pretending to be forced, throwing the pot also carries the risk of beating the face.

The content in that pit is the same as that of most articles you can search on 100 poisons, but the title of my pit is very good: “What is yield (Part I)”, which implies that everyone still has the next article, so the title also needs a certain technical content.

I firmly believe that after reading the last article, the spicy chicken here would like to say the sentence “teddy bear” most (this is a cultural attribute, not subject to your will):

Returning to today’s keynote, I would like to stress a few points:

  • Although the title of the article contains the key words “yield and Xiecheng”, in fact yield is not Xiecheng. It seems that many people equate yield and Xiecheng directly. Yield is essentially a Generator. Its English name is Generator.
  • Yield can only be used in function, but using yield is no longer a traditional function, and if you try to use yield elsewhere than function, you will be beaten in the face.
  • The most important function of yield is to interrupt the execution of a lump of code and then voluntarily give up CPU control to passer-by A.; Then it can resume operation from the place where it was interrupted in some ways. This is more awesome. If you request a server API that takes 10 sec onds, you can give up the CPU to the passer-by. Roughly speaking, the above process is even the basic concept of coordination.

Multi-thread and multi-process are the scheduling in which the operating system participates, while coordination is the scheduling that the user realizes autonomously. The key point of coordination is actually “the user layer realizes autonomous scheduling”, which probably means “emancipated serfs sing”.

Now I will experience a “emancipated serf” through a lump of code. You can feel it:

<?php
function gen1() {
  for( $i = 1; $i <= 10; $i++ ) {
    echo "GEN1 : {$i}".PHP_EOL;
    // sleep没啥意思,主要就是运行时候给你一种切实的调度感,你懂么
    // 就是那种“你看!你看!尼玛,我调度了!卧槽”
    sleep( 1 );
    // 这句很关键,表示自己主动让出CPU,我不下地狱谁下地狱
    yield;
  }
}
function gen2() {
  for( $i = 1; $i <= 10; $i++ ) {
    echo "GEN2 : {$i}".PHP_EOL;
    // sleep没啥意思,主要就是运行时候给你一种切实的调度感,你懂么
    // 就是那种“你看!你看!尼玛,我调度了!卧槽”
    sleep( 1 );
    // 这句很关键,表示自己主动让出CPU,我不下地狱谁下地狱
    yield;
  }
}
$task1 = gen1();
$task2 = gen2();
while( true ) {
  // 首先我运行task1,然后task1主动下了地狱
  echo $task1->current();
  // 这会儿我可以让task2介入进来了
  echo $task2->current();
  // task1恢复中断
  $task1->next();
  // task2恢复中断
  $task2->next();
}

The above code execution results are as follows:

Although I have said everything here, there must still be some people who cannot get “so, what happened?” . You should know that if there is no yield in function gen1 and function gen2 but a normal function, you cannot interrupt the for loop, such as the following code:

<?php
function gen1() {
  for( $i = 1; $i <= 10; $i++ ) {
    echo "GEN1 : {$i}".PHP_EOL;
    sleep( 1 );
  }
}
function gen2() {
  for( $i = 1; $i <= 10; $i++ ) {
    echo "GEN2 : {$i}".PHP_EOL;
  }
}
gen1();
gen2();
// 看这里,看这里,看这里!
// 上面的代码一旦运行,一定是先运行完gen1函数中的for循环
// 其次才能运行完gen2函数中的for循环,绝对不会出现
// gen1和gen2交叉运行这种情况

I seem to have mastered yield already.

After writing here, I started bouncing, which is different from the previous three days when I couldn’t bounce a fart. This time I bounced out a typical application scenario: curl. Next, we will modify gen1 into a time-consuming curl network request based on the above hot chicken code. gen2 will write content to a text file. our purpose is to actively release the CPU after the time-consuming curl starts, and let gen2 write the file to realize the maximum utilization of the CPU.

<?php
$ch1 = curl_init();
// 这个地址中的php,我故意sleep了5秒钟,然后输出一坨json
curl_setopt( $ch1, CURLOPT_URL, "http://www.selfctrler.com/index.php/test/test1" );
curl_setopt( $ch1, CURLOPT_HEADER, 0 );
$mh = curl_multi_init();
curl_multi_add_handle( $mh, $ch1 );
function gen1( $mh, $ch1 ) {
  do {
    $mrc = curl_multi_exec( $mh, $running );
    // 请求发出后,让出cpu
    yield;
  } while( $running > 0 );
  $ret = curl_multi_getcontent( $ch1 );
  echo $ret.PHP_EOL;
  return false;
}
function gen2() {
  for ( $i = 1; $i <= 10; $i++ ) {
    echo "gen2 : {$i}".PHP_EOL;
    file_put_contents( "./yield.log", "gen2".$i, FILE_APPEND );
    yield;
  }
}
$gen1 = gen1( $mh, $ch1 );
$gen2 = gen2();
while( true ) {
  echo $gen1->current();
  echo $gen2->current();
  $gen1->next();
  $gen2->next();
}

After the above code is run, we can wait for curl to initiate the request within 5 seconds and complete the file writing function at the same time. If we change to a normal PHP program, we can only block the file writing until curl gets the result.

The article is too long, just like “the old lady’s foot-binding cloth is smelly and long”. therefore, if you make a small change to the code, you will not write it at the end!

<?php
$ch1 = curl_init();
// 这个地址中的php,我故意sleep了5秒钟,然后输出一坨json
curl_setopt( $ch1, CURLOPT_URL, "http://www.selfctrler.com/index.php/test/test1" );
curl_setopt( $ch1, CURLOPT_HEADER, 0 );
$mh = curl_multi_init();
curl_multi_add_handle( $mh, $ch1 );
function gen1( $mh, $ch1 ) {
  do {
    $mrc = curl_multi_exec( $mh, $running );
    // 请求发出后,让出cpu
    $rs = yield;
    echo "外部发送数据{$rs}".PHP_EOL;
  } while( $running > 0 );
  $ret = curl_multi_getcontent( $ch1 );
  echo $ret.PHP_EOL;
  return false;
}
function gen2() {
  for ( $i = 1; $i <= 10; $i++ ) {
    echo "gen2 : {$i}".PHP_EOL;
    file_put_contents( "./yield.log", "gen2".$i, FILE_APPEND );
    $rs = yield;
    echo "外部发送数据{$rs}".PHP_EOL;
  }
}
$gen1 = gen1( $mh, $ch1 );
$gen2 = gen2();
while( true ) {
  echo $gen1->current();
  echo $gen2->current();
  $gen1->send("gen1");
  $gen2->send("gen2");
}

We have revised the content:

Changed $gen1->next () to $gen1->send(“gen1 “)

In function gen1, yield has a return value and prints it out

This incident tells us that yield and send can communicate in two directions. at the same time, it tells us that send can be used to restore the original interrupted code and can carry information back when resuming the interruption. Write here, do you think the usable value of this thing is higher than the original?

I know, someone must have said, “Lao Li, what you wrote in your code is really spicy chicken! You promised before-only write spicy chicken code in the company’s production environment. But look at you, this spicy chicken halo has enveloped the demo. You have not even let go of the demo! what do you have to say? !” . Brother dei, “it’s not that it can’t be used.” Moreover, I tell you, it is not enough for curl demo to understand yield for the above point. There are two or three more yield articles to follow. It is still bad code that disgusts you and likes to watch it or not. I advise you to relax your mind and think about what you have experienced with such bad code. What else can’t you experience?

At the end of the article, I’d like to add a little story: Actually, yield has been added since PHP 5.5. The author of this module is Nikita Popov, and the name on the Internet is Nikic. We know that the main force of the PHP7 generation is Huixinchen, and the main force of the next generation is Nikic. As early as 2012, Nikic published an article on PHP yield multitasking. I posted the link for everyone to enjoy-http://nikic.github.io/2012/1 …

Recently, a WeChat public number was opened, and all articles are here.

图片描述