PHP多cURL性能比顺序file_get_contents差

时间:2016-08-09 06:06:38

标签: php apache curl curl-multi

我正在编写一个界面,我必须在其中启动4个http请求以获取一些信息。

我以两种方式实现了界面:

  1. 使用顺序file_get_contents。
  2. 使用多卷曲。
  3. 我用jmeter对2个版本进行了基准测试。结果表明,当jmeter中只有1个线程发出请求时,多卷曲比顺序file_get_contents要好得多,但是当100个线程时更糟糕。

    问题是:哪个会导致多卷曲的糟糕表现?

    我的多卷曲代码如下:

    $_POST

1 个答案:

答案 0 :(得分:3)

1。简单优化

  • 如果curl_multi_select失败,你应该睡大约2500微秒 实际上,它有时会在每次执行时彻底失败 没有睡眠,您的CPU资源会被许多while (true) { }循环占用
  • 如果在某些(并非所有)请求完成后您没有执行任何操作, 你应该让最大超时时间更长。
  • 您的代码是为旧的libcurls编写的。截至libcurl版本7.2,
    状态CURLM_CALL_MULTI_PERFORM不再出现。

所以,以下代码

$running = null;
$mrc = null;
do
{
    $mrc = curl_multi_exec( $master , $running );
}
while ( $mrc == CURLM_CALL_MULTI_PERFORM );
while ( $running && $mrc == CURLM_OK )
{
    if (curl_multi_select( $master ) != - 1)
    {
        do
        {
            $mrc = curl_multi_exec( $master , $running );
        }
        while ( $mrc == CURLM_CALL_MULTI_PERFORM );
    }
}

应该是

curl_multi_exec($master, $running);
do
{
    if (curl_multi_select($master, 99) === -1)
    {
        usleep(2500);
        continue;
    }
    curl_multi_exec($master, $running);
} while ($running);

注意

只有在您想要执行类似......

之类的操作时,才应调整curl_multi_select的超时值
curl_multi_exec($master, $running);
do
{
    if (curl_multi_select($master, $TIMEOUT) === -1)
    {
        usleep(2500);
        continue;
    }
    curl_multi_exec($master, $running);
    while ($info = curl_multi_info_read($master))
    {
        /* Do something with $info */
    }
} while ($running);

否则,该值应该非常大。
(但是,PHP_INT_MAX太大; libcurl将其视为无效值。)

2。在一个PHP过程中轻松实验

我使用我的并行cURL执行程序库进行了测试:mpyw/co

(准备工作for不合适,应该是by,抱歉我的英语不好xD)

<?php 

require 'vendor/autoload.php';

use mpyw\Co\Co;

function four_sequencial_requests_for_one_hundread_people()
{
    for ($i = 0; $i < 100; ++$i) {
        $tasks[] = function () use ($i) {
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => 'example.com',
                CURLOPT_FORBID_REUSE => true,
                CURLOPT_RETURNTRANSFER => true,
            ]);
            for ($j = 0; $j < 4; ++$j) {
                yield $ch;
            }
        };
    }
    $start = microtime(true);
    yield $tasks;
    $end = microtime(true);
    printf("Time of %s: %.2f sec\n", __FUNCTION__, $end - $start);
}

function requests_for_four_hundreds_people()
{
    for ($i = 0; $i < 400; ++$i) {
        $tasks[] = function () use ($i) {
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => 'example.com',
                CURLOPT_FORBID_REUSE => true,
                CURLOPT_RETURNTRANSFER => true,
            ]);
            yield $ch;
        };
    }
    $start = microtime(true);
    yield $tasks;
    $end = microtime(true);
    printf("Time of %s: %.2f sec\n", __FUNCTION__, $end - $start);
}

Co::wait(four_sequencial_requests_for_one_hundread_people(), [
    'concurrency' => 0, // Zero means unlimited
]);

Co::wait(requests_for_four_hundreds_people(), [
    'concurrency' => 0, // Zero means unlimited
]);

我尝试了五次以获得以下结果:

enter image description here

我也尝试了相反的顺序(第三个请求被踢了xD):

enter image description here

这些结果表示过多的并发TCP连接实际上会降低吞吐量

3。高级优化

3-A。适用于不同的目的地

如果要针对少数和多个并发请求进行优化,以下脏解决方案可能会对您有所帮助。

  1. 使用apcu_add / apcu_fetch / apcu_delete分享请求者的数量。
  2. 按当前值切换方法(顺序或并行)。
  3. 3-B。对于相同的目的地

    CURLMOPT_PIPELINING会帮助你。 此选项将同一目标的所有HTTP / 1.1连接捆绑到一个TCP连接中。

    curl_multi_setopt($master, CURLMOPT_PIPELINING, 1);