「分享创造」在Workerman中使用GuzzleHttp协程版实现无感异步请求

cclilshy

简介

PRipple协程引擎是一个100%原生PHP代码实现的现代化协程引擎,不依赖任何扩展,
可以在任何PHP环境(FPM/CLI)下运行, 本组件是基于该引擎开发的GuzzleHttp的异步请求插件,
既保留了GuzzleHttp的所有功能(上传/下载等),又支持协程异步请求

环境要求

PHP >= 8.1

Linux/Unix 系统

安装

Composer 安装

composer require cclilshy/p-ripple-drive

Webman 配置

配置 config/server.php 文件

<?php
return [
    //...
    'event_loop' => \Psc\Drive\Workerman\PDrive::class,
];

Workerman 配置

//...
Worker::$eventLoop = \Psc\Drive\Workerman\PDrive::class;

使用方法

手动创建

public function index(Request $request): string
{
    $handle = new \Psc\Plugins\Guzzle\PHandler([
       'pool' => 1 // 是否启用Http长连接
    ]);
    $client = new \GuzzleHttp\Client(['handle' => $handle]);

    // 发送请求(即使该请求耗时很长, 也不会堵塞当前进程的其他请求)
    $response = $client->get('http://www.baidu.com');
    return $response->getBody()->getContents();
}

全局使用(荐)

public function index(Request $request): string
{
    $client = \P\Plugin::Guzzle();

    // 发送请求(即使该请求耗时很长, 也不会堵塞当前进程的其他请求)
    $response = $client->get('http://www.baidu.com');
    return $response->getBody()->getContents();
}

效果演示

public function index(Request $request): string
{
    for ($i = 0; $i < 100; $i++) {
        \P\async(function () use ($i) {
            $response           = \P\Plugin::Guzzle()->get('https://www.qq.com/');
            $time               = microtime(true);
            $responseStatusCode = $response->getStatusCode();
            var_dump("[{$time}]request {$i} status: {$responseStatusCode}");
        });
    }
    return 'hello,world';
}

1181 11 6
11个评论

兔白白

... 感觉这玩意 出生的有点晚了。 对于耗时的业务流程,现在常规做法都是丢redis队列里面慢慢跑了..不过 感觉这个比队列还是方便些,比如一些保存文件。之类的操作,那就可以直接把保存的路径返回回去 后台这边慢慢保存文件了。 不需要东写一句 西写一句了

初心by

  • 暂无评论
liudada1204

  • 暂无评论
软饭工程师

截图
截图
请问 安装了扩展,config/server.php 也修改了配置,为什么还是提示async 方法不存在

xiaoming

稳定吗

  • 暂无评论
深林孤鹰

太强了,真是个好东西!

  • 暂无评论
深林孤鹰

刚才测试的时候,用了之前文章里的:
$response = \P\await(\P\Plugin::Guzzle()->getAsync('https://www.baidu.com'));
不知为何没效果;

另外,截图
好像缺了很多访问,我用的webman单进程测试的。。

  • cclilshy 2024-08-11

    $response = \P\Plugin::Guzzle()->get('https://www.baidu.com'); 直接这样就可以兄弟

  • 深林孤鹰 2024-08-11

    嗯,后来我这样写了,但是出现了上图的问题,很多request没有出现

  • cclilshy 2024-08-12

    可能是并发高出现的请求错误,try捕获以下看看

  • 深林孤鹰 2024-08-12

    试了一下:

        for ($i = 0; $i < 30; $i++) {
            \P\async(function () use ($i) {
                try {
                    $response = \P\Plugin::Guzzle()->get('https://www.qq.com');
                    $time = microtime(true);
                    $responseStatusCode = $response->getStatusCode();
                    var_dump("[{$time}] request {$i} status: {$responseStatusCode}");
                } catch (\Exception $e) {
                    var_dump($e->getMessage());
                } catch (\Throwable $e) {
                    var_dump($e->getMessage());
                } finally {
                }
            });

    没有捕获到异常,仍然是丢了Request,有时能丢个70%左右。。。

  • cclilshy 2024-08-12

    设置一个timeout看看

  • cclilshy 2024-08-12

    按照guzzle的方式设置就行了

  • 深林孤鹰 2024-08-12

    搞定了,确实是Request timeout的问题,谢谢大佬~
    另外请问一下这个能用在生产环境吗?

  • cclilshy 2024-08-12

    最近在写单元测试,到覆盖率全面那时call你

  • 深林孤鹰 2024-08-12

    好的,辛苦,我作为用户来帮忙测试^^
    昨天看了文档,可能我比较菜,有些地方不太明白,有群能交流吗?

  • cclilshy 2024-08-12

    可以在webman群call我嘿嘿

  • 深林孤鹰 2024-08-12

    了解~

  • cclilshy 19天前

    上车吧兄弟

  • 深林孤鹰 15天前

    已在我个人项目中使用,等你的ORM+协程出来我上正式项目

软饭工程师

截图
你好,这个好像发送post 请求接收不到数据,是我使用方式有问题吗

    public function test11()
    {
        $data = ['name' => 'tom', 'age' => 10];
        \P\async(function () use ($data) {
            \P\Plugin::Guzzle()->post('http://127.0.0.1:18787/index/test12', [
                'json' => $data,
            ]);
        });
        return 'ok';
    }
    public function test12(Request $request)
    {
        $res = $request->all();
        var_dump($res);
        return true;
    }
    public function test13()
    {
        $data = ['name' => 'tom', 'age' => 10];
        $client = new \GuzzleHttp\Client();
        $client->post('http://127.0.0.1:18787/index/test12', [
            'json' => $data,
        ]);
    }
  • cclilshy 2024-08-13

    你好,debug一下webman控制器$request的header()和recvBuffer部分看看呢?

  • cclilshy 2024-08-13

    这是头部没有自动加入content-length导致的,
    已在下个版本解决,详见
    https://github.com/cloudtay/p-ripple-core/commit/f9cc669d9eeac09d44b2673a31140ba146470973

    现在可以通过这个方式解决1

    \P\async(function () {
        $data = ['name' => 'tom', 'age' => 10];
        $body = json_encode($data);
        \P\Plugin::Guzzle()->post('http://127.0.0.1:8787/index/test12', [
            'body'    => $body,
            'headers' => [
                'Content-Type'   => 'application/json',
                'Content-Length' => strlen($body),
            ],
        ]);
    });
  • 软饭工程师 2024-08-13

    截图牛啊,上面那个问题好了,测试发现协程发送超过1000个请求就会失败,进程直接退出

        public function test9(Request $request): string
        {
            for ($i = 0; $i < 1000; $i++) {
                \P\async(function () use ($i) {
                    $response = \P\Plugin::Guzzle()->get('https://www.qq.com/');
                    $time = microtime(true);
                    $responseStatusCode = $response->getStatusCode();
                    var_dump("[{$time}]request {$i} status: {$responseStatusCode}");
                });
            }
            return 'hello,world';
        }
  • cclilshy 2024-08-13

    😂正常,系统最大文件描述符拉高一下

tanhongbin

大佬 这玩意 windows系统安装不了呀 扩展没有 哈哈

  • 暂无评论
liwenshu

windows 可以用吗

  • tanhongbin 13天前

    没有扩展 windows 天生没有多进程扩展哈哈 搜索不到

  • cclilshy 12天前

    @tanhongbin 可以用的最新版本已经兼容windows

  • tanhongbin 12天前

    win10 composer 安装的时候 会让你安装 多进程扩展 然而win php没有 哈哈

  • cclilshy 12天前

    --ignore-platform-reqs就可以, 暂时还没移掉这个声明而已

  • tanhongbin 12天前

    一会试试

shiroi

跟amp不差不多吗

cclilshy

420
积分
0
获赞数
0
粉丝数
2024-04-09 加入
×
🔝