Table of Contents
yield and generator
Generator
yield
Others
Generator and coroutine
Coroutine Programming
Summary
Home Backend Development PHP Tutorial Detailed introduction to coroutines in php (code)

Detailed introduction to coroutines in php (code)

Sep 13, 2018 pm 04:57 PM
php coroutine

This article first introduces the concept of generator, focusing on the usage of yield and the interface of generator. The coroutine part briefly explains the principles of coroutines and matters that should be paid attention to in PHP coroutine programming.

PHP has introduced generator (Generator) since 5.5, based on which coroutine programming can be realized. This article starts with a review of generators and then transitions to coroutine programming.

yield and generator

Generator

Generator is a data type that implements the iterator interface. The generator instance cannot be obtained through new, and there is no static method to obtain the generator instance. The only way to get a generator instance is to call the generator function (a function containing the yield keyword). Calling the generator function directly returns a generator object, and the code within the function starts executing when the generator is running.

First go to the code to intuitively experience yield and generators:

# generator1.php
function foo() {
    exit('exit script when generator runs.');
    yield;
}

$gen = foo();
var_dump($gen);
$gen->current();

echo 'unreachable code!';

# 执行结果
object(Generator)#1 (0) {
}
exit script when generator runs.
Copy after login

fooThe function contains the yield keyword and transforms into a generator function. Calling foo does not execute any code in the function body, but instead returns a generator instance. After the generator runs, the code within the foo function is executed and the script ends.

As the name suggests, generators can be used to generate data. It’s just that the way it generates data is different from other functions: the generator returns data through yield instead of return; After yield returns data, the generator function does not It will be destroyed, it just pauses the operation, and it can be resumed from the pause in the future; the generator will return (only) one data if it is run once, and multiple data will be returned if it is run multiple times; if the generator is not called to obtain data, the code in the generator will lie there. The so-called "moving every time" refers to the way the generator generates data.

The generator implements the iterator interface. To obtain the generator data, you can use foreach loop or manual current/next/valid. The following code demonstrates data generation and traversal:

# generator2.php
function foo() {
  # 返回键值对数据
  yield "key1" => "value1";
  $count = 0;
  while ($count < 5) {
    # 返回值,key自动生成
    yield $count;
    ++ $count;
  }
  # 不返回值,相当于返回null
  yield;
}

# 手动获取生成器数据
$gen = foo();
while ($gen->valid()) {
  fwrite(STDOUT, "key:{$gen->key()}, value:{$gen->current()}\n");
  $gen->next();
}

# foreach 遍历数据
fwrite(STDOUT, "\ndata from foreach\n");
foreach (foo() as $key => $value) {
    fwrite(STDOUT, "key:$key, value:$value\n");
}
Copy after login

yield

yieldThe keyword is the core of the generator, which allows ordinary functions to differentiate (evolve) into generator functions. yield means "giving up". When the program executes to the yield statement, it will pause execution, yield the CPU and return control to the caller. The next execution will continue from the interruption point. implement. When control returns to the caller, the yield statement can return the value to the caller. generator2.phpThe script demonstrates the three forms of yield return values:

  1. yield $key => $value: Returns the key and value of the data;

  2. yield $value: Returns data, key is allocated by the system;

  3. yield: Returns null value, key is allocated by the system;

yieldAllows the function to pause, continue execution at any time, and return data to the caller. If external data is needed to continue execution, this work is provided by the send function of the generator: the variable that appears on the left side of yield will receive the variable from send value. Let’s look at a common send function usage example:

function logger(string $filename) {
  $fd = fopen($filename, 'w+');
  while($msg = yield) {
    fwrite($fd, date('Y-m-d H:i:s') . ':' . $msg . PHP_EOL);
  }
  fclose($fd);
}

$logger = logger('log.txt');
$logger->send('program starts!');
// do some thing
$logger->send('program ends!');
Copy after login

send The ability to have two-way data communication between generators and the outside: yieldReturn data; send Provide support data for continued operation. Since send allows the generator to continue executing, this behavior is similar to the next interface of the iterator, where next is equivalent to send(null).

Others

  1. $string = yield $data; expression is not legal before PHP7 and requires parentheses: $string = (yield $data);

  2. ##PHP5 generator function cannot

    return value, after PHP7 it can return value and pass the of the generator getReturnGet the returned value.

  3. PHP7 adds the

    yield from syntax to implement generator delegation.

  4. The generator is a one-way iterator, and

    rewind cannot be called after it is started.

Summary

Compared with other iterators, generators have the characteristics of low performance overhead and easy coding. Its role is mainly reflected in three aspects:

  1. Data generation (producer), returning data through yield;

  2. Data consumption (consumer) ), consume the data from send;

  3. implements the coroutine.

Regarding generators and basic usage in PHP, it is recommended to read the blog post of

2gua: PHP Generator is lively, interesting and easy to understand.

Coroutine programming

Coroutine (coroutine) is a subroutine that can be interrupted and resumed at any time. The

yield keyword allows the function to have this ability, so it can be used For coroutine programming.

Processes, threads and coroutines

Threads belong to processes, and a process can have multiple threads. A process is the smallest unit for computer allocation of resources, and a thread is the smallest unit for computer scheduling and execution. Both processes and threads are scheduled by the operating system.

Coroutines can be regarded as "user-mode threads" and require user programs to implement scheduling. Threads and processes are scheduled by the operating system to run alternately in a "preemptive" manner, and coroutines actively give up the CPU to run alternately in a "negotiative" manner. Coroutines are very lightweight, coroutine switching does not involve thread switching, and the execution efficiency is high. The greater the number, the better the advantages of coroutines can be reflected.

Generator and coroutine

The coroutine implemented by the generator is a stackless coroutine, that is, the generator function only has a function frame, which is attached to the caller's stack during runtime for execution. Unlike the powerful stackful coroutine, the generator cannot control the direction of the program after it is paused, and can only passively return control to the caller; the generator can only interrupt itself, not the entire coroutine. Of course, the advantage of the generator is that it is highly efficient (you only need to save the program counter when pausing) and is simple to implement.

Coroutine Programming

Speaking of coroutine programming in PHP, I believe most people have read this blog post reprinted (translated) by Brother Niao: Using coroutines to achieve multiple functions in PHP Task scheduling. The original author nikic is the core developer of PHP, the initiator and implementer of the generator function. If you want to learn more about generators and coroutine programming based on them, nikic's RFC on generators and the articles on Niaoge's website are must-reads.

Let’s first look at the working method of coroutines based on generators: coroutines work collaboratively, that is, coroutines actively give up the CPU to achieve alternate running of multiple tasks (that is, concurrent multitasking, but not parallel); A generator can be regarded as a coroutine. When the yield statement is executed, the CPU control is returned to the caller, and the caller continues to execute other coroutines or other codes.

Let’s look at the difficulty in understanding Brother Bird’s blog. Coroutines are very lightweight, and thousands of coroutines (generators) can exist in a system at the same time. The operating system does not schedule coroutines, and the work of arranging coroutine execution falls on developers. Some people don’t understand the coroutine part of Brother Niao’s article because it says there is little coroutine programming (writing coroutines mainly means writing generator functions), but they spend a lot of time implementing a coroutine scheduler (scheduler or kernel). : Simulates the operating system and performs fair scheduling on all coroutines. The general thinking of PHP development is: I wrote these codes, and the PHP engine will call my codes to get the expected results. Coroutine programming requires not only writing code to do the work, but also writing code to instruct these codes when to work. If you don’t have a good grasp of the author’s thinking, it will naturally be more difficult to understand. It needs to be scheduled by itself, which is a disadvantage of the generator coroutine compared to the native coroutine (async/await form).

Now that we know what coroutine is, what can it be used for? The coroutine gives up the CPU on its own to cooperate and efficiently utilize the CPU. Of course, the time to give up should be when the program is blocked. Where will the program block? User-mode code rarely blocks, and blocking is mainly caused by system calls. The majority of system calls are IO, so the main application scenario of coroutines is network programming. In order to make the program high performance and high concurrency, the program should execute asynchronously and not block. Since asynchronous execution requires notifications and callbacks, writing callback functions cannot avoid the problem of "callback hell": code readability is poor, and the program execution process is scattered among layers of callback functions. There are two main ways to solve callback hell: Promise and coroutines. Coroutines can write code in a synchronous manner and are recommended in high-performance network programming (IO-intensive).

Let’s look back at coroutine programming in PHP. In PHP, coroutine programming is implemented based on generators. It is recommended to use coroutine frameworks such as RecoilPHP and Amp. These frameworks have already written schedulers. If you develop a generator function directly on it, the kernel will automatically schedule execution (if you want a function to be scheduled for execution in a coroutine mode, just add yield to the function body. ). If you don’t want to use the yield method for coroutine programming, we recommend swoole or its derivative framework, which can achieve a coroutine programming experience similar to golang and enjoy the development efficiency of PHP.

If you want to use the original PHP coroutine programming, a scheduler similar to the one in Niao Ge's blog is essential. The scheduler schedules the execution of the coroutine. After the coroutine is interrupted, control returns to the scheduler. Therefore, the scheduler should always be in the main (event) loop, that is, when the CPU is not executing the coroutine, it should be executing the scheduler code. When running without a coroutine, the scheduler should block itself to avoid consuming the CPU (Niao Ge's blog uses the built-in select system call), wait for the event to arrive, and then execute the corresponding coroutine. During the running of the program, except for scheduler blocking, the coroutine should not call blocking APIs during running.

Summary

In coroutine programming, the main function of yield is to transfer control without worrying about its return value (basically yieldThe returned value will be send directly during the next execution). The focus should be on the timing of the transfer of control and how the coroutine operates.

In addition, it needs to be explained that coroutines have little to do with asynchrony, and it also depends on the running environment support. In the conventional PHP operating environment, even if promise/coroutine is used, it is still blocked synchronously. No matter how awesome the coroutine framework is, sleep is no longer easy to use. As an analogy, even if JavaScript does not use promise/async technologies, it is asynchronous and non-blocking.

Through generators and Promise, coroutine programming similar to await can be implemented. There is a lot of relevant code on Github and will not be given in this article.

Related recommendations:

$_SERVER in PHP Detailed introduction

Detailed introduction to output_buffering in PHP, outputbuffering_PHP tutorial

The above is the detailed content of Detailed introduction to coroutines in php (code). For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 brings several new features, security improvements, and performance improvements with healthy amounts of feature deprecations and removals. This guide explains how to install PHP 8.4 or upgrade to PHP 8.4 on Ubuntu, Debian, or their derivati

How To Set Up Visual Studio Code (VS Code) for PHP Development How To Set Up Visual Studio Code (VS Code) for PHP Development Dec 20, 2024 am 11:31 AM

Visual Studio Code, also known as VS Code, is a free source code editor — or integrated development environment (IDE) — available for all major operating systems. With a large collection of extensions for many programming languages, VS Code can be c

How do you parse and process HTML/XML in PHP? How do you parse and process HTML/XML in PHP? Feb 07, 2025 am 11:57 AM

This tutorial demonstrates how to efficiently process XML documents using PHP. XML (eXtensible Markup Language) is a versatile text-based markup language designed for both human readability and machine parsing. It's commonly used for data storage an

PHP Program to Count Vowels in a String PHP Program to Count Vowels in a String Feb 07, 2025 pm 12:12 PM

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

7 PHP Functions I Regret I Didn't Know Before 7 PHP Functions I Regret I Didn't Know Before Nov 13, 2024 am 09:42 AM

If you are an experienced PHP developer, you might have the feeling that you’ve been there and done that already.You have developed a significant number of applications, debugged millions of lines of code, and tweaked a bunch of scripts to achieve op

Explain late static binding in PHP (static::). Explain late static binding in PHP (static::). Apr 03, 2025 am 12:04 AM

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What are PHP magic methods (__construct, __destruct, __call, __get, __set, etc.) and provide use cases? What are PHP magic methods (__construct, __destruct, __call, __get, __set, etc.) and provide use cases? Apr 03, 2025 am 12:03 AM

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.

See all articles