Guzzle并发去请求图片并保存到本地

现在有个小需求,需要用Guzzle并发去请求图片并保存到本地,并发的数量是不固定的,下面测试代码,请教大家指点一下!

public function onGoodsSynchronizationEvent(GoodsSynchronizationEvent $goodsSynchronizationEvent,Client $client){

        $requests = function (array $imageInfo) {
            foreach ($imageInfo as $image){
                yield new Request('GET', $image['url']);
            }
        };

        $pool = new Pool($client, $requests($goodsSynchronizationEvent->imageInfo), [
            'concurrency' => 5,
            'fulfilled' => function ($response, $index) {
                // this is delivered each successful response
            },
            'rejected' => function ($reason, $index) {
                // this is delivered each failed request
            },
        ]);

        // Initiate the transfers and create a promise
        $promise = $pool->promise();

        // Force the pool of requests to complete.
        $promise->wait();
    }

我只了解请求单个可以这样使用

$client->get($rul,['save_to'=>$fileName);
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 7

这是看了文档后修改后的代码,折腾了半天

public function onGoodsSynchronizationEvent(GoodsSynchronizationEvent $goodsSynchronizationEvent,Client $client){

        $option = collect($goodsSynchronizationEvent->imageInfo)->each(function ($item){

            !file_exists($item['path']) && super_built($item['path']);

            return [
                'save_to'=>$item['path'].'/'.$item['name']
            ];
        });

        $requests = function (array $imageInfo) {
            foreach ($imageInfo as $image){
                yield new Request('GET', $image['url'],[]);
            }
        };

        $pool = new Pool($client, $requests($goodsSynchronizationEvent->imageInfo), [
            'concurrency' => 10,
            'fulfilled' => function (Response $response, int $index) use ($option){

                if ($image = $option->offsetGet($index)){
                    $getContents = $response->getBody()->getContents();
                   //获取图片直接保存
                    file_put_contents($image['save_to'],$getContents);
                }
            }
        ]);

        // Initiate the transfers and create a promise
        $promise = $pool->promise();

        // Force the pool of requests to complete.
        $promise->wait();
    }
1年前 评论

你这 $imageInfo 都已经是一个完整地址的数组了,你直接用文档里面前一个例子不就好了么…… 🤨,还跑去搞相对复杂的 Pool。

文档中的 当希望发送的请求数量不确定时,可以使用 GuzzleHttp Pool 对象。 可不是指你这样的场景,这里应该是指像 Redis 的 scan 和 ES 的 scroll API 这种情况,或者从远程(迭代器)不断有获取的情况下。

而你这里图片地址都已经是一个确定的数组了,就直接用文档种前面的里面就好了。

1年前 评论
微加加的朋友 (楼主) 1年前
mouyong
1年前 评论
微加加的朋友 (楼主) 1年前
mouyong (作者) 1年前

@Rache1 你说的列子是不是这个并发请求?

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client(['base_uri' => 'http://httpbin.org/']);

// Initiate each request but do not block
$promises = [
    'image' => $client->getAsync('/image'),
    'png'   => $client->getAsync('/image/png'),
    'jpeg'  => $client->getAsync('/image/jpeg'),
    'webp'  => $client->getAsync('/image/webp')
];

// Wait for the requests to complete; throws a ConnectException
// if any of the requests fail
$responses = Promise\Utils::unwrap($promises);

// You can access each response using the key of the promise
echo $responses['image']->getHeader('Content-Length')[0];
echo $responses['png']->getHeader('Content-Length')[0];

// Wait for the requests to complete, even if some of them fail
$responses = Promise\Utils::settle($promises)->wait();

// Values returned above are wrapped in an array with 2 keys: "state" (either fulfilled or rejected) and "value" (contains the response)
echo $responses['image']['state']; // returns "fulfilled"
echo $responses['image']['value']->getHeader('Content-Length')[0];
echo $responses['png']['value']->getHeader('Content-Length')[0];
1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!