资讯专栏INFORMATION COLUMN

php异步编程

antyiwei / 1551人阅读

摘要:配合或者自身的已经可以满足很多请求异步化的需求。协程与异步既然协程可以被中断,那么只要在程序发起请求后发起事件循环,然后用返回,然后程序继续执行主程序部分,等事件返回后触发函数,执行或来继续执行协程部分。

前言

我对 php 异步的知识还比较混乱,写这篇是为了整理,可能有错。

传统的 php-fpm 一个进程执行一个请求,要达到多少并发,就要生成多少个进程。更糟糕的是每次请求都需要重新编译执行,导致并发一直上不来。因此出现了 Swoole 和 WorkerMan 两个国内流行的常驻内存框架[1]。这两个框架原理都是通过事件循环,让程序一直停留在内存,等待外部请求,达到高并发。

为什么需要异步 先来看一个例子

在工作目录下新建文件 slowServer.php


开启服务

$ php -S localhost:8081 slowServer.php

开另一个终端,安装依赖

$ pecl install event # 安装 event 扩展
$ composer require workerman/workerman
$ composer require react/http-client:^0.5.9

新建文件 worker.php

require_once __DIR__ . "/vendor/autoload.php";
use WorkermanWorker;
use WorkermanConnectionAsyncTcpConnection;
use AmpArtaxResponse;

$http_worker = new Worker("http://0.0.0.0:8082");

$http_worker->count = 1; // 只开一个进程

$http_worker->onMessage = function($connection, $host) {
    echo 1;
    $data = file_get_contents("http://localhost:8081");
    $connection->send($data);
};

Worker::runAll();

开启服务器

php worker.php start

在浏览器开启两个标签,都打开网址 http://localhost:8082 。这时可以看到终端输出“1”,过了一会儿又输出“1”,原因是8081服务器在处理第一个请求的时候阻塞在了等待8081返回之中,等第一个请求结束后,才开始处理第二个请求。也就是说请求是一个一个执行的,要达到多少个并发,就要建立多少个进程,跟 php-fpm 一样。现在修改一下代码

$http_worker->onMessage = function($connection, $host) {
    echo 1;
    $loop    = Worker::getEventLoop();
    $client  = new ReactHttpClientClient($loop);
    $request = $client->request("GET", "http://localhost:8081");
    $request->on("error", function(Exception $e) use ($connection) {
        $connection->send($e);
    });
    $request->on("response", function ($response) use ($connection) {
        $response->on("data", function ($data) use ($connection) {
            $connection->send($data);
        });
    });
    $request->end();
};

现在打开服务,再在浏览器发起请求,发现第二个“1”在请求后就马上输出了,而这时第一个请求还没结束。这表明进程不再阻塞,并发量取决于 cpu 和 内存,而不是进程数。

为什么需要异步

通过上面的例子已经很明白了,reactphp 框架通过把 http 请求变成异步,让 onMessage 函数变成非阻塞,cpu 可以去处理下一个请求。即从 cpu 循环等待 8081 返回,变成了 epoll 等待。

异步的意义在于把 cpu 从 io 等待中解放出来,可以处理其他计算任务。 如果你想知道怎么用框架实现异步,看到这里就可以了。WorkerMan 配合 ReactPHP 或者自身的 AsyncTcpConnection 已经可以满足很多 io 请求异步化的需求。下面继续讨论这些框架是怎么做到异步的。

哪些地方应该被做成异步

通过上面的例子已经知道一旦执行到不需要 cpu,但是要等待 io 的时候,应该把 io 的过程做成异步。

实现事件循环

上面的例子是通过 reactphp 把 http 请求变成了异步,其实 WorkerMan 框架本身也是异步的,下面来看看 WorkerMan 是怎么使 onMessage 函数可以异步接受请求。先来新建下面这个文件 react.php

add();
$eventBase->loop(); // 开始循环

开始执行

$ php react.php

在另一个终端执行

telnet 127.0.0.1 8081

这时就会看到第一个终端输出"1"。

我之前写过一篇文章《php使用epoll》,是这篇文章的基础。那篇文章里事件回调是通过定时来实现,即

$event->add($seconds);

而这里,事件回调是通过检测 fd 是否有写入内容来实现,这个过程不需要 cpu 参与。当 fd 有内容写入时,会调函数 "react",这时开始使用 cpu。如果这时候进程执行另一个异步请求,比如用 reactphp 框架请求一个网页,那么程序会让出 cpu,此时如果有另一个请求进来,就可以回调执行另一个 "react" 函数。由此提高了并发量。

协程 生成器 Generater

这是生成器的 PHP 官方文档 http://php.net/manual/zh/lang...


生成器就是每次程序执行到 yield 的时候保存状态,然后返回 $i,是否继续执行 gen_one_to_three 里的循环,取决于主程序是否继续调用

什么是协程

上面的程序另一种写法是


由此可见,协程就是一种对函数的封装,使其变成一种可以被中断的函数,行为更像是子进程或子线程,而不是函数。协程的具体写法这里不细写,因为协程的写法十分复杂,可能需要再做一层封装才能好用。

协程与异步

既然协程可以被中断,那么只要在程序发起请求后发起事件循环,然后用 yield 返回,然后程序继续执行主程序部分,等事件返回后触发函数,执行 Generatot::next() 或 Generator::send() 来继续执行协程部分。封装好后就好像没有异步回调函数一样,和同步函数很像。

现在已经有 ampphp 和 swoole 两个框架封装了协程,有兴趣可以了解一下。


国外还有 https://amphp.org 和 https://reactphp.org 这两个框架

博客地址:http://b.ljj.pub

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30010.html

相关文章

  • PHP并发IO编程之路

    摘要:下文如无特殊声明将使用进程同时表示进程线程。收到数据后服务器程序进行处理然后使用向客户端发送响应。现在各种高并发异步的服务器程序都是基于实现的,比如。 并发 IO 问题一直是服务器端编程中的技术难题,从最早的同步阻塞直接 Fork 进程,到 Worker 进程池/线程池,到现在的异步IO、协程。PHP 程序员因为有强大的 LAMP 框架,对这类底层方面的知识知之甚少,本文目的就是详细介...

    Riddler 评论0 收藏0
  • nodejs异步编程详解

    摘要:四异步编程解决方案模式模式一定程度上缓解了嵌套回调的问题,只会处在未完成完成态失败态中的一种,只会从未完成转化为完成态或者失败态,不能逆转。 一、从一个简单的案例开始 fs.readdir(path.join(__dirname, ./index.js), (err, files) => { files.foreach((filename, index) => { ...

    inapt 评论0 收藏0
  • PHP异步编程异步的本质

    摘要:实现异步的方式有哪些提供了一些异步方法那它们底层是用哪种方式实现的呢实现异步的方式有线程方式进程方式复用线程方式和进程方式类似有异步请求时开一个线程或者进程获取到数据后线程间可以直接共享数据进程间可以通过进程通信机制,如共享内存管道等方式进 实现异步的方式有哪些? swoole提供了一些异步方法, 那它们底层是用哪种方式实现的呢? 实现异步的方式有: 线程方式 进程方式 IO复用 ...

    lushan 评论0 收藏0
  • PHP异步编程: 基于PHP实(chao)现(xi) NODEJS web框架KOA

    摘要:异步编程基于实现框架说明偶然间在上看到有赞官方仓库的手把手教你实现与。由于此前用过,对于的洋葱模型叹为观止。文档中是基于扩展进行开发,而对并不友好,向来习惯在下开发的我一鼓作气,将改写并兼容了此项目。 PHP异步编程: 基于 PHP 实(chao)现(xi) NODEJS web框架 KOA 说明 偶然间在 GITHUB 上看到有赞官方仓库的 手把手教你实现co与Koa 。由于此前用过...

    freewolf 评论0 收藏0
  • 聊聊 2018 年后端技术趋势

    摘要:现在在后端业务开发编程方面,技术力量强的团队已经开始将技术栈从同步模式切换为异步了。使用这些技术方案是无法兼容已有程序的。影响了异步回调技术栈的普及。将会成为未来后端开发领域的主流技术方案。 今天太忙,少写一点,后面再补充。 异步模式 Go 语言越来越热门,很多大型互联网公司后端正在转向 GO 。Java 圈知名的服务化框架 Dubbo 也宣布转型异步模式。这是一个大趋势,异步模式已经...

    Miyang 评论0 收藏0

发表评论

0条评论

antyiwei

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<