最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Guzzle Promise 链式(嵌套)请求和控制并发数量

    正文概述 转载于:掘金(居正)   2021-02-14   787

    本文内容:Guzzle采用promise方式,通过链式调用requestAsync、getAsync、postAsync等函数嵌套异步请求,并且通过Pool控制并发数量的方法。

    需求:

    • 需要能够发送异步请求,并且控制一个并发数量。
    • 在一个请求发送后需要用到这个请求返回的内容,才能发送下一个请求

    类似场景:异步获取指定的一个图像URL列表的图片内容,并把每一张图片都上传到另一个图床上。

    需要用到的环境:php 7.2以上版本+Guzzle v7,Guzzle v6的async系列函数有问题,有时候会莫名其妙地输出responseBody,好坑啊。

    这里就用httpbin.org来做演示。

    首先创建guzzle对象:

    $guzzle=new \GuzzleHttp\Client();
    

    正确姿势

    $promises=[];// 1
    $respList=[];
    foreach (range(0,49) as $i){
        $promises[]=function() use ($guzzle,&$respList,$i){// 1, 2
            $promise=$guzzle->getAsync('https://httpbin.org/uuid');
            $promise->then(function($resp) use ($guzzle,&$respList,$i){
                $uuid=json_decode($resp->getBody())->uuid;
                if(empty($uuid)){
                    return;// 4
                }
                echo $i.'获取uuid成功:'.$uuid.PHP_EOL;
                $promise2=$guzzle->getAsync('https://httpbin.org/anything?uuid='.$uuid);
                $promise2->then(function($resp2) use (&$respList,$i){// 2
                    $respList[]=json_decode($resp2->getBody());
                    echo $i.'上传uuid成功'.PHP_EOL;
                },function($reason){
                    echo '上传uuid失败 '.$reason.PHP_EOL;
                });
                return $promise2;// 3
            },function($reason){
                echo '获取uuid失败 '.$reason.PHP_EOL;
            });
            return $promise;// 3
        };
    }
    $pool=new \GuzzleHttp\Pool($guzzle,$promises,[
        'concurrency'=>5,
        'fulfilled'=>function($index){
    
        },
        'rejected'=>function($reason,$index){
    
        }
    ]);
    $pool->promise()->wait();
    echo count($respList);
    

    要点,对应上面代码中的注释:

    1. 用一个promises数组来接收,在循环里面添加一个调用之后返回async promise对象的函数。不要直接添加promise对象
    2. 对外部变量进行写操作的时候,需要加上&引用,类似指针,不然外部变量不会实质更改
    3. 新建promise、配置promise->then、返回promise三步走,包括里层的promise也是
    4. 这个地方IDE会提示缺少参数,原因是需要返回一个promise,但其实是不一定需要的。

    参考:stackoverflow.com/questions/4…

    错误姿势

    1.没有用一个function来yield async 请求

    $promises=[];
    $respList=[];
    foreach (range(0,49) as $i){
        $promise=$guzzle->getAsync('https://httpbin.org/uuid');
        $promise->then(function($resp) use ($guzzle,&$respList,$i){
            $uuid=json_decode($resp->getBody())->uuid;
            if(empty($uuid)){
                return;
            }
            echo $i.'获取uuid成功:'.$uuid.PHP_EOL;
            $promise2=$guzzle->getAsync('https://httpbin.org/anything?uuid='.$uuid);
            $promise2->then(function($resp2) use (&$respList,$i){
                $respList[]=json_decode($resp2->getBody());
                echo $i.'上传uuid成功'.PHP_EOL;
            },function($reason){
                echo '上传uuid失败 '.$reason.PHP_EOL;
            });
            return $promise2;
        },function($reason){
            echo '获取uuid失败 '.$reason.PHP_EOL;
        });
        $promises[]=$promise;
    }
    

    参考:github.com/guzzle/guzz…

    2.在第一个promise的then里面调用了第二个promise的wait

    foreach (range(0,49) as $i){
        $promises[]=function() use ($guzzle,&$respList,$i){
            $promise=$guzzle->getAsync('https://httpbin.org/uuid');
            $promise->then(function($resp) use ($guzzle,&$respList,$i){
                $uuid=json_decode($resp->getBody())->uuid;
                if(empty($uuid)){
                    return;
                }
                echo $i.'获取uuid成功:'.$uuid.PHP_EOL;
                $promise2=$guzzle->getAsync('https://httpbin.org/anything?uuid='.$uuid);
                $promise2->then(function($resp2) use (&$respList,$i){
                    $respList[]=json_decode($resp2->getBody());
                    echo $i.'上传uuid成功'.PHP_EOL;
                },function($reason){
                    echo '上传uuid失败 '.$reason.PHP_EOL;
                });
                $promise2->wait();// 1
            },function($reason){
                echo '获取uuid失败 '.$reason.PHP_EOL;
            });
            return $promise;
        };
    }
    

    见代码中的注释1处。guzzle的promise在没有调用wait函数的时候是不会真正执行的。而由于PHP的promise并不是真正的多线程,在promise里面调用另一个promise的wait仍然会阻塞。

    参考:github.com/guzzle/prom…

    3.误用了EachPromise代替Pool

    $pool=new \GuzzleHttp\Promise\EachPromise($promises,[
        'concurrency'=>5,
        'fulfilled'=>function($index){
    
        },
        'rejected'=>function($reason,$index){
    
        }
    ]);
    

    如果这个错误和前面提到的第一个错误同时犯,就会产生看起来concurrency无效的情况。

    参考:github.com/guzzle/guzz…


    起源地下载网 » Guzzle Promise 链式(嵌套)请求和控制并发数量

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元