Table of Contents
一个简单的单线程 TCP Server" >一个简单的单线程 TCP Server
启动测试程序" >启动测试程序
运行结果" >运行结果
CoWorker购物车服务" >CoWorker购物车服务
运行命令" >运行命令
Home Backend Development PHP Tutorial Learn advanced usage of PHP yield

Learn advanced usage of PHP yield

Jun 30, 2020 pm 05:37 PM
php yield

Learn advanced usage of PHP yield

Opening Chapter

When I first came into contact with yield of PHP, I felt, yield What kind of black technology is it? Baidu: yield——coroutine, generator. Many articles are talking about Iterator, Generater, hey~, this thing is a supplement to PHP iterator. Turn a few more pages and you’ll find Go coroutine. Out of curiosity, I clicked and looked at Go Coroutine, which contained words like Concurrency, Thread, Pipeline Communication, etc. wc, nb, this is black technology. Come back and look at PHP, and I want to switch to Go every minute.

Related learning recommendations: PHP programming from entry to proficiency

yield syntax to join PHP

yieldThe syntax was added to PHP in version 5.5. It is used with iterators. The function is process control code, and goto,return Similar.

The following is a small example of yield provided by the official. Through the execution results, we can analyze that when the code is executed to yield $i, it will return $i, After echo "$value\n", goto for ($i = 1; $i , yes! PHP's yield is a syntax that can go out and go in. In the z code, seven in and seven out, <code>$i was sent out safely.

<?phpfunction  gen_one_to_three() {
    for ($i = 1; $i <= 7; $i++) {
        //注意变量$i的值在不同的yield之间是保持传递的。
        yield $i;
    }}$generator = gen_one_to_three();foreach ($generator as $value) {
    echo "$value\n";}// output12...67
Copy after login

What problems did we encounter

Writing code is to solve the problem. Let's take a look at what problems they encountered: As for PHP officials, they need to introduce yield to everyone in a concise and concise manner. Some netizens need to complete large file operations within limited resources. And our bird brother. I faced a group of PHPers who were dissatisfied with the current yield tutorials that were still at the elementary level. I took a task scheduler as an example and told them an advanced usage of yield.

php.net: Generator syntax,
How PHP reads large files,
Wind and Snow Corner: Using coroutines to implement multi-task scheduling in PHP.

proposed Question, and then use yield to answer it. Seeing the above answer, I think this PHP coroutine is nothing more than that ( compared with Go coroutine).

There is a saying - A good question is more important than the answer. At present, the majority of netizens have not asked better and more difficult questions for yield.

yieldFor this in-and-out syntax, many examples are to use yield as an iterator, or to use low memory to read very large textExcel,csv or something, no matter how advanced it is, it is used to implement a simple task scheduler, and the code of this scheduler is similar at first glance.

Let me ask the question

Just like a good question, it is more valuable than the answer

  1. Use PHP Implement a Socket Server that can receive requests and return the server's time.

Okay, this is the first question, foreshadowing. Official answer

  1. On the original code, we add a requirement. When the Socket Server processes requests, it depends on other Socket Servers and also needs the Client function. That is, he can receive requests and initiate requests to other servers.

This is the second question and also the foreshadowing.

  1. The original Socket Server can only serve one customer at the same time. We hope to realize a non-blocking I/O Socket Server. This Server has the Socket Client function and supports Concurrency Process received requests and actively initiated requests. It is not required to use multi-threading or multi-process.

This question is still foreshadowing. These questions are very dry. You can think about it. The answers to questions 2 and 3 are all placed in a script: nio_server.php

In the above code, I listed a specific business, which is that the user requests a shopping cart add-on action. As for the shopping cart service, it needs to interact with product services, inventory services, and preferential services to verify the feasibility of the add-on action. . There are synchronous and asynchronous methods to request and compare.

There is a lot of code to follow, I have put gitee links. For usage, see readme.md

  1. Last question: In PHP, if you write code synchronously, will the program be executed asynchronously? How to adjust the code.

Tip: This is related to the yield syntax of PHP.

Another reminder: yield What are the grammatical features, In and out!

Looking at our code, synchronous, asynchronous, In and out What did you think of?

When you see the code, in synchronous processing mode, these three functions checkInventory checkProduct checkPromo initiate a request and wait for the return in turn. As a result, after these three functions are executed, the client request is responded to.

异步处理模式下,这三个函数发起请求完毕后,代码就跳出循环了,然后是在select()下的一个代码分支中接收请求, 并收集结果。每次收到结果后判断是否完成,完成则响应客户端。

那么能不能这样:在异步处理的流程中,当 Server收到 自己发起的 client 有数据响应后,代码跳到 nio_server.php 的 247行呢,这样我们的收到请求校验相关的代码就能放到这里,编码能就是同步,容易理解。不然,client 的响应处理放在 280 行以后,不通过抓包,真的很难理解,执行了第 247 行代码后,紧接着是从 280 行开始的。

诶~这里是不是有 进进出出 那种感觉了~ 代码从 247 行出去,开始监听发出 Client 响应,收到返回数据,带着数据再回到 247 行,继续进行逻辑校验,综合结果后,再响应给客户端。

用yield来解决问题

基于 yield 实现的,同步编码,"异步"I/OSocket Server 就实现了。代码。

这里 “异步” 打了引号,大佬别扣这个字眼了。 该是非阻塞I/O

不等大家的答案了,先上我的结果代码吧,代码呢都放在这个目录下了。

gitee https://gitee.com/xupaul/PHP-generator-yield-Demo/tree/master/yield-socket

运行测试代码

clone 代码到本地后,需要拉起4个 command 命令程序:

拉起3个第三方服务

## 启动一个处理耗时2s的库存服务$ php ./other_server.php 8081 inventory 2## 启动一个处理耗时4s的产品服务$ php ./other_server.php 8082 product 4## 监听8083端口,处理一个请求 耗时6s的 promo 服务$ php ./other_server.php 8083 promo 6
Copy after login

启动购物车服务

## 启动一个非阻塞购物车服务$ php ./async_cart_server.php 

## 或者启动一个一般购物车服务$ php ./cart_server.php
Copy after login

发起用户请求

$ php ./user_client.php
Copy after login

运行结果呢如下,通过执行的时间日志,可得这三个请求是并发发起的,不是阻塞通讯。

在看我们的代码,三个函数,发起socket请求,没有设置callback,而是通过yield from 接收了三个socket的返回结果。

也就是达到了,同步编码,异步执行的效果。

运行结果

非阻塞模式

client 端日志:

通过以上 起始时间结束时间 ,就看到这三个请求耗时总共就6s,也就按照耗时最长的promo服务的耗时来的。也就是说三个第三方请求都是并发进行的。

cart server 端日志:

而 cart 打印的日志,可以看到三个请求一并发起,并一起等待结果返回。达到非阻塞并发请求的效果。

阻塞模式

client 端日志:

以上是阻塞方式请求,可以看到耗时 12s。也就是三个服务加起来的耗时。

cart server 端日志:

cart 服务,依次阻塞方式请求第三方服务,顺序执行完毕后,共耗时12s,当然如果第一个,获第二个服务报错的话,会提前结束这个检查。会节约一点时间。

工作原理

这里就是用到了 yield 的工作特点——进进出出,在发起非阻塞socket请求后,不是阻塞方式等待socket响应,而是使用yield跳出当前执行生成器,等待有socket响应后,在调用生成器的send方法回到发起socket请求的函数内,在 yield from Async::all() 接收数据响应数据搜集完毕后,返回。

和Golang比一比

考虑到网速原因,我这就放上一个国内教程链接:Go 并发 教程

php的协程是真协程,而Go是披着协程外衣的轻量化线程(“协程”里,都玩上“锁”了,这就是线程)。

我个人偏爱,协程的,觉得线程的调度有一定随机性,因此需要锁机制来保证程序的正确,带来了额外开销。协程的调度(换入换出)交给了用户,保证了一段代码执行连续性(当然进程级上,还是会有换入换出的,除非是跨进程的资源访问,或者跨机器的资源访问,这时,就要用到分布式锁了,这里不展开讨论),同步编码,异步执行,只需要考虑那个哪个方法会有IO交互会协程跳出即可。

和NodeJS比划一下

Javascript 和 PHP 两个脚本语言有很多相似的地方,弱类型,动态对象,单线程,在Web领域生态丰富。不同的是,Javascript在浏览器端一开始就是异步的(如果js发起网络请求只能同步进行,那么你的网页渲染线程会卡住),例如AjaxsetTimeoutsetInterval,这些都是异步+回调的方式工作。

基于V8引擎而诞生的NodeJS,天生就是异步的,在提供高性能网络服务有很大的优势,不过它的IO编码范式么。。。刚开始是 回调——毁掉地狱,后来有了Promise——屏幕竖起来看,以及Generator——遇事不绝yield一下吧,到现在的Async/Await——语法糖?真香!

可以说JS的委员非常勤快,在异步编程范式的标准制定也做的很好(以前我尝试写NodeJS时,几个回调就直接把我劝退了),2009年诞生的NodeJS有点后来居上的意思。目前PHP只是赶上了协程,期待PHP的Async/Await语法糖的实现吧。

PHP yield 使用注意事项

一旦使用上 yield 后,就必须注意调用函数是,会得到函数结果,还是 生成器对象。PHP 不会自动帮你区别,需要你手动代码判断结果类型—— if ($re instanceof \Generator) {}, 如果你得到的是 生成器,但不希望去手动调用 current() 去执行它,那么在生成器前 使用 yield from 交给上游(框架)来解决。

爆改 Workerman

博客写到这,就开始手痒痒了,看到Workerman框架,我在基础上二开,使其能——同步编码,异步执行

代码已放到:PaulXu-cn/CoWorkerman.git

目前还是dev阶段,大家喜欢可以先 体验一波。

$ composer require paulxu-cn/co-workerman
Copy after login
Copy after login
<?php// file: ./examples/example2/coWorkermanServer.php , 详细代码见github$worker = new CoWorker(&#39;tcp://0.0.0.0:8080&#39;);// 设置fork一个子进程$worker->count = 1;$worker->onConnect = function (CoTcpConnection  $connection) {
    try {
        $conName = "{$connection->getRemoteIp()}:{$connection->getRemotePort()}";
        echo PHP_EOL . "New Connection, {$conName} \n";

        $re = yield from $connection->readAsync(1024);
        CoWorker::safeEcho(&#39;get request msg :&#39; . $re . PHP_EOL );

        yield from CoTimer::sleepAsync(1000 * 2);

        $connection->send(json_encode(array(&#39;productId&#39; => 12, &#39;re&#39; =>true)));

        CoWorker::safeEcho(&#39;Response to :&#39; . $conName . PHP_EOL . PHP_EOL);
    } catch (ConnectionCloseException $e) {
        CoWorker::safeEcho(&#39;Connection closed, &#39; . $e->getMessage() . PHP_EOL);
    }};CoWorker::runAll();
Copy after login

这里设置fork 一个worker线程,处理逻辑中带有一个sleep() 2s的操作,依然不影响他同时响应多个请求。

## 启动CoWorker服务$ php ./examples/example2/coWorkermanServer.php start## 启动请求线程$ php ./examples/example2/userClientFork.php
Copy after login

绿色箭头——新的请求,红色箭头——响应请求

从结果上看到,这一个worker线程,在接收新的请求同时,还在回复之前的请求,各个连接交错运行。而我们的代码呢,看样子就是同步的,没有回调。

好的,这里我们做几个简单的微服务模拟实际应用,这里模拟 用户请求端购物车服务库存服务产品服务。 模拟用户请求加购动作,购物车去分别请求 库存,产品 校验用户是否可以加购,并响应客户请求是否成功。

代码我就不贴了,太长了,麻烦移步 CoWorkerman/example/example5/coCartServer.php

## 启动库存服务$ php ./examples/example5/otherServerFork.php 8081 inventory 1## 启动产品服务$ php ./examples/example5/otherServerFork.php  8082 product 2
Copy after login
## 启动CoWorker 购物车服务$ php ./examples/example5/coCartServer.php start
Copy after login
## 用户请求端$ php ./examples/example5/userClientFork.php
Copy after login

黄色箭头——新的用户请求,蓝色箭头——购物车发起库存,产品检查请求,红色箭头——响应用户请求

从图中看到也是用1个线程服务多个连接,交错运行。

好的,那么PHP CoWorkerman 也能像 NodeJS 那样用 Async/Await 那样同步编码,异步运行了。

快来试试这个 CoWorkerman 吧:

$ composer require paulxu-cn/co-workerman
Copy after login
Copy after login

工作原理

先上图:

The upper part of the picture is the work lane diagram of Workerman, and the lower part of the picture is the work lane diagram of CoWorkerman.

workerman When the worker process encounters the blocking function, it will wait for IO to return. If there is a new request at this time, then the idle workers will compete for this new connection.

In the above picture of worker5, I describe a AsyncTCPConnection usage situation. A non-blocking request is initiated in the worker and the callback function is registered, and then the program continues to run to the end. When an asynchronous request responds, you need to respond in other ways (such as initiating another request yourself to inform the requester).

In the figure belowCoWorkerman, there are also multiple Workers competing for new requests. When worker1 receives a new request, a generator will be generated, and an asynchronous request will be initiated in the generator and registered. Respond to the callback. After requesting a response, return to the place where the generator jumped out (yield) and continue executing the code.

Initiate an asynchronous request and register a callback function. These default tasks have been done in the CoWorkerman framework. The work in the callback function is: receive the data and send it to the person who initiated the request. Builder.

In this example, multiple requests are initiated by calling Promise:all() and the results are returned. Wait for all responses to be returned before continuing to run the generator

After the program yield jumps out, the worker is in the event loop state ($event->loop()), that is, multi-channel monitoring: request port, third-party client End request response port. At this time, if:

  1. has a new request, it will compete with other worker for the new request. If competition occurs, a new generator will be generated in the worker.
  2. If the client responds, the callback function is called.
  3. If the client responds, continue running the generator program.

From 1, we can assume that if there is only one Worker, then the Worker can continue to accept processing even if the previous request is not completed. Next request. That is, CoWorkerman can run under a single Worker and process multiple requests concurrently.

Of course, there is also a premise here. Blocking functions cannot be run in single Worker mode. Once blocked, subsequent requests will be blocked on the network card. Therefore, unless you know your code very well, if you use a third-party library, then I still recommend that you run CoWorkerman in multi-Worker mode, and when blocking, there are other WorkerPocket new requests.

The meaning of CoWorkerman

  1. Use synchronous code to initiate asynchronous requests. Multiple requests can be concurrent. Change from IO serial waiting to Wait in parallel to reduce fearless wait times. Improve the efficiency of business programs without reducing code readability.
  2. Through the event loop in one thread, multiple requests are processed as much as possible, which alleviates the frequent thread switching caused by one request and one thread, and improves operating efficiency from the core.

CoWorkerman Ecological Niche

is suitable for applications that handle pure Socket requests, such as Workerman Gateway, or Big front end Integrate multiple servicesRPCThe results will be returned to the first three pages after integrationSuch a scenario.

The log record is The most basic requirement of each program. Since the file writing function is blocking, it is recommended to use message queue or redis queue, or skip Logstash and directly throw Elasticsearch.

CoWorkerman has his limitations and his own position.

Summary

Okay~This is the end of PHP coroutine coding to network asynchronous coding. If you have many doubts after reading this article, please leave a message to ask questions. , if yield don’t remember the grammar well, you can read the previous articles in this series to review them.

If it works, please do it three times. CoWorkerman Thank you!

Learn advanced usage of PHP yield

The above is the detailed content of Learn advanced usage of PHP yield. 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)
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
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

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

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

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,

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 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