Guzzle

Guzzle

Guzzle教程或者说笔记。
性能:该框架确实能提升性能,测试windows平台上,使用Pool的方式来批量请求,性能只能提升不到1倍。1000次请求,由普通代码17秒提升至12秒左右,而且设置了不10、30、50、100的并发,但是时间上并没有太大的改变。另外,使用js来进行请求,反而时间能提升至1秒左右。大概提升到了10倍的性能。所以,我在想,这个库的实现原理是啥?如何做到异步请求的?待研究。

相关测试,在Guzzle示例.zip。

资源

手册地址

https://guzzle-cn.readthedocs.io/zh_CN/latest/psr7.html#requests

相关概念

Request

请求。参见例子3中,yield的请求,应该来说,这个对象,并未真正发送请求,只是包装了一下请求的参数。待执行

Promise对象

$client->postAsync 这些异步请求,会产生这样的对象。

Response

响应,常用方法。$results[‘image1’]->getBody()

使用例子

例子1

<?php
include "vendor/autoload.php";
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;


$t0=microtime(true);

$client = new Client([
    'base_uri' => 'http://10.20.24.165',
    'timeout'  => 10.0,
]);
try{
    $promise = $client->requestAsync('GET','demo.php');
}catch(\Exception $e){
    echo $e->getMessage();
}

$spend = microtime(true) - $t0;
echo "done:$spend s\n";

$promise->then(
    function (ResponseInterface $res) {
        echo 'suchuanchao####';
        echo $res->getStatusCode() . "\n";
    },
    function (RequestException $e) {
        echo $e->getMessage() . "\n";
        echo $e->getRequest()->getMethod();
    }
);
$spend = microtime(true) - $t0;
echo "done:$spend s\n";
sleep(8);

例子2

<?php
include "vendor/autoload.php";
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;

$t0=microtime(true);

$client = new Client([
    'base_uri' => 'http://10.20.24.165',
    'timeout'  => 10.0,
]);

$promises = [
    'image1' => $client->getAsync('demo.php'),
    'image2' => $client->getAsync('demo.php'),
    'image3' => $client->getAsync('demo.php'),
    'image4' => $client->getAsync('demo.php'),
    'image5' => $client->getAsync('demo.php'),
    'image6' => $client->getAsync('demo.php'),
    'image7' => $client->getAsync('demo.php'),
    'image8' => $client->getAsync('demo.php'),
    'image9' => $client->getAsync('demo.php'),
    'image10' => $client->getAsync('demo.php'),
];
//好像是将上面数组的整体请求完。
$results = Promise\unwrap($promises);
// var_dump($results['image1']->getHeader('Content-Length'));
// var_dump($results['image2']->getHeader('Content-Length'));
// var_dump($results['image3']->getHeader('Content-Length'));
// var_dump($results['image4']->getHeader('Content-Length'));
// var_dump($results['image5']->getHeader('Content-Length'));
// var_dump($results['image6']->getHeader('Content-Length'));
// var_dump($results['image7']->getHeader('Content-Length'));
// var_dump($results['image8']->getHeader('Content-Length'));
// var_dump($results['image9']->getHeader('Content-Length'));
// var_dump($results['image10']->getHeader('Content-Length'));


// var_dump($results['image1']->getStatusCode());
// var_dump($results['image2']->getStatusCode());
// var_dump($results['image3']->getStatusCode());
// var_dump($results['image4']->getStatusCode());
// var_dump($results['image5']->getStatusCode());
// var_dump($results['image6']->getStatusCode());
// var_dump($results['image7']->getStatusCode());
// var_dump($results['image8']->getStatusCode());
// var_dump($results['image9']->getStatusCode());
// var_dump($results['image10']->getStatusCode());

// var_dump($results['image1']->getBody());
// var_dump($results['image2']->getBody());
// var_dump($results['image3']->getBody());
// var_dump($results['image4']->getBody());
// var_dump($results['image5']->getBody());
// var_dump($results['image6']->getBody());
// var_dump($results['image7']->getBody());
// var_dump($results['image8']->getBody());
// var_dump($results['image9']->getBody());
// var_dump($results['image10']->getBody());

echo $results['image1']->getBody();
echo $results['image2']->getBody();
echo $results['image3']->getBody();
echo $results['image4']->getBody();
echo $results['image5']->getBody();
echo $results['image6']->getBody();
echo $results['image7']->getBody();
echo $results['image8']->getBody();
echo $results['image9']->getBody();
echo $results['image10']->getBody();


$spend = microtime(true) - $t0;
echo "done:$spend s\n";
sleep(8);

例子3

请求池Pool

<?php
include "vendor/autoload.php";


use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;

use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;

$t0=microtime(true);

//客户端也不能少
$client = new Client([
    // Base URI is used with relative requests
    'base_uri' => 'http://10.20.24.165',
    // You can set any number of default request options.
    'timeout'  => 10.0,
]);

$requests = function ($total) {
    $uri = 'http://localhost/demo.php';
    for ($i = 0; $i < $total; $i++) {
        // yield new Request('GET', $uri);
        yield new Request('GET', $uri);
    }
};

$pool = new Pool($client, $requests(100), [
    //并发量,好像每次都一次性返回
    'concurrency' => 30,
    // 成功的回调
    'fulfilled' => function ($response, $index) {
        // this is delivered each successful response
        echo '#3333' .PHP_EOL;
        echo $response->getBody().PHP_EOL;
    },
    //失败后的回调
    'rejected' => function ($reason, $index) {
        echo '#22222';
        // this is delivered each failed request
    },
]);


$promise = $pool->promise();
$promise->wait();

$spend = microtime(true) - $t0;
echo "done:$spend s\n";
sleep(8);

例子4

Post请求。aplication-json格式的请求。

function getPhoneNum($mail_no){
    global $client;
    $url = 'http://10.19.160.165:29010/order/phone';
    $params = [
        'json'=>[
            'shipId'=>$mail_no,
            'systemId' => 'yunchou'
        ]
    ];
    $response = $client->post($url,$params);
    $data = json_decode($response->getBody(),true);
    var_dump($data);
}

对应普通的curl代码的相似功能:

/**
     * 发送json格式的数据到服务器。
     * @return mixed $result 接口调用返回结果。
     */
    public static function postJson($url, array $post = NULL, array $options = array())
    {
        $jsonStr = \json_encode($post);
        $defaults = array(
            CURLOPT_POST => 1,
            CURLOPT_HEADER => 0,
            CURLOPT_URL => $url,
            CURLOPT_FRESH_CONNECT => 1,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_FORBID_REUSE => 1,
            CURLOPT_TIMEOUT => 5,
            CURLOPT_POSTFIELDS => $jsonStr,
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/json; charset=utf-8',
                'Content-Length: ' . strlen(json_encode($post))
            ),
        );
        $ch = curl_init();
        curl_setopt_array($ch, ($options + $defaults));
        if( ! $result = curl_exec($ch))
        {
            throw new \Exception(curl_error($ch));
        }
        curl_close($ch);
        return $result;
    }

例子5

卡在$requests = function ($mails) 函数呢。返回new Request,但是对于提交的请求头,跟上面的弄混淆了,下面的应该是关联数据格式,上面的请求头是普通的数组。因为这一步卡了很久。

重点:注意Request对象的headers写法,不同于上面curl格式的请求头。

<?php
include "vendor/autoload.php";
use GuzzleHttp\Client;
use GuzzleHttp\Promise;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\Exception\RequestException;

$t0=microtime(true);
//客户端也不能少
$client = new Client([
    'base_uri' => 'http://10.19.160.165:29010',
    'timeout'  => 10.0,
]);

$requests = function ($mails) {
    global $client;
    $url = 'http://10.19.160.165:29010/order/phone';
    foreach ($mails as $mail_no) {
        // yield new Request('GET', $uri);

        $params = [
            'shipId'=>$mail_no,
            'systemId' => 'yunchou'
        ];
        $header = [
            'Content-Type'=>'application/json; charset=utf-8',
            // 'Content-Length' => ' . strlen(json_encode($params))',
        ];
        // yield new Request('POST', $url,$params);
        yield new Request('POST',$url,$header,json_encode($params) );
    }
};
$mails = [
    '4000148909728',
    '4000158397760',
    '3189066031209',
];
$pool = new Pool($client, $requests($mails), [
    //并发量,好像每次都一次性返回
    'concurrency' => 30,
    // 成功的回调
    'fulfilled' => function ($response, $index) {
        // this is delivered each successful response
        echo '#3333' .PHP_EOL;
        echo $response->getBody().PHP_EOL;
    },
    //失败后的回调
    'rejected' => function ($reason, $index) {
        echo '#22222';
        // this is delivered each failed request
    },
]);


function getPhoneNum($mail_no){
    global $client;
    $url = 'http://10.19.160.165:29010/order/phone';
    $response = $client->post($url,$params);
    $data = json_decode($response->getBody(),true);
    var_dump($data);
}


$promise = $pool->promise();
$promise->wait();

// getPhoneNum('4000148909728');
// getPhoneNum('4000158397760');
// getPhoneNum('3189066031209');