当前位置: 首页 > 知识库问答 >
问题:

狂饮异步请求不是真的异步?

松琦
2023-03-14

我们正在尝试使用 guzzle 执行并发异步请求。在浏览了一些资源(例如这样和这样)之后,我们提出了一些在下面共享的代码。但是,它没有按预期工作。

看起来Guzzle正在同步而不是异步地处理这些请求。

出于测试目的,我们点击一个内部url,它会Hibernate5秒钟。当并发数为10时,我们预计所有10个请求最初将被排队并几乎同时发送到服务器,在那里它们将等待5秒钟,然后几乎所有的请求将几乎同时完成。这将使guzzle客户端从迭代器中获取10个新请求,依此类推。

    $iterator = function() {
        $index = 0;
        while (true) {
            $client = new Client(['timeout'=>20]);
            $url = 'http://localhost/wait/5' . $index++;
            $request = new Request('GET',$url, []);
            echo "Queuing $url @ " . (new Carbon())->format('Y-m-d H:i:s') . PHP_EOL;
            yield $client
                ->sendAsync($request)
                ->then(function(Response $response) use ($request) {
                    return [$request, $response];
                });
        }
    };

    $promise = \GuzzleHttp\Promise\each_limit(
        $iterator(),
        10,  /// concurrency,
        function($result, $index) {
            /** GuzzleHttp\Psr7\Request $request */
            list($request, $response) = $result;
            echo (string) $request->getUri() . ' completed '.PHP_EOL;
        },
        function(RequestException $reason, $index) {
            // left empty for brevity
        }
    );
    $promise->wait();

我们发现,在第一个请求完成之前,古斯从未提出过第二个请求。依此类推。

Queuing http://localhost/wait/5/1 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/2 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/3 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/4 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/5 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/6 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/7 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/8 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/9 @ 2017-09-01 17:15:28
Queuing http://localhost/wait/5/10 @ 2017-09-01 17:15:28
http://localhost/wait/5/1 completed
Queuing http://localhost/wait/5/11 @ 2017-09-01 17:15:34
http://localhost/wait/5/2 completed
Queuing http://localhost/wait/5/12 @ 2017-09-01 17:15:39
http://localhost/wait/5/3 completed
Queuing http://localhost/wait/5/13 @ 2017-09-01 17:15:45
http://localhost/wait/5/4 completed
Queuing http://localhost/wait/5/14 @ 2017-09-01 17:15:50 

操作系统/版本信息

  • Ubuntu
  • PHP/7.1.3
  • GUZLE http/6.2.1
  • 卷曲/7.47.0

该问题可能与\GuzzleHttp\Promise\each_limit有关..这可能没有足够快地启动或解决promise。我们可能需要欺骗外部的< code>tick。

共有1个答案

卫宁
2023-03-14

在示例代码中,您将为要发出的每个请求创建一个新的 GuzzleHttp\Client 实例。这似乎并不重要,但是,在 GuzzleHttp\Client 的实例化期间,如果未提供任何处理程序,它将设置默认处理程序。(然后,此值将向下传递给通过客户端发送的任何请求,除非它被覆盖。

注意:它从这个函数中确定要使用的最佳处理程序。不过,它很可能会默认为< code>curl_mutli_exec。

这有什么重要的?底层处理程序负责同时跟踪和执行多个请求。通过每次创建一个新的处理程序,没有一个请求被正确地分组并一起运行。要更深入地了解这一点,请查看< code>curl_multi_exec文档。

所以,你有两种处理方式:

通过客户端传递到迭代器:

$client = new GuzzleHttp\Client(['timeout' => 20]);

$iterator = function () use ($client) {
    $index = 0;
    while (true) {
        if ($index === 10) {
            break;
        }

        $url = 'http://localhost/wait/5/' . $index++;
        $request = new Request('GET', $url, []);

        echo "Queuing $url @ " . (new Carbon())->format('Y-m-d H:i:s') . PHP_EOL;

        yield $client
            ->sendAsync($request)
            ->then(function (Response $response) use ($request) {
                return [$request, $response];
            });

    }
};

$promise = \GuzzleHttp\Promise\each_limit(
    $iterator(),
    10,  /// concurrency,
    function ($result, $index) {
        /** @var GuzzleHttp\Psr7\Request $request */
        list($request, $response) = $result;
        echo (string)$request->getUri() . ' completed ' . PHP_EOL;
    }
);
$promise->wait();

或者在其他地方创建处理程序并将其传递给客户端:(虽然我不知道为什么要这样做,但它就在那里!)

$handler = \GuzzleHttp\HandlerStack::create();

$iterator = function () use ($handler) {
    $index = 0;
    while (true) {
        if ($index === 10) {
            break;
        }

        $client = new Client(['timeout' => 20, 'handler' => $handler])
        $url = 'http://localhost/wait/5/' . $index++;
        $request = new Request('GET', $url, []);

        echo "Queuing $url @ " . (new Carbon())->format('Y-m-d H:i:s') . PHP_EOL;

        yield $client
            ->sendAsync($request)
            ->then(function (Response $response) use ($request) {
                return [$request, $response];
            });

    }
};

$promise = \GuzzleHttp\Promise\each_limit(
    $iterator(),
    10,  /// concurrency,
    function ($result, $index) {
        /** @var GuzzleHttp\Psr7\Request $request */
        list($request, $response) = $result;
        echo (string)$request->getUri() . ' completed ' . PHP_EOL;
    }
);
$promise->wait();
 类似资料:
  • 我希望我的请求触发一些长时间运行的操作,这些操作应该在后台执行。我编写了以下实现,应该在后台处理我的操作,但实际上我的请求是同步执行的: 在日志中,我看到以下内容: 我看到我的在另一个线程中执行,但出于某种原因,我的原始请求等待sleep完成 更新1:

  • 我正在使用Kafka客户端1.0.0库中的KafkaProducer,根据文档,该方法是

  • 问题内容: 我有一个ajax问题: 如果循环6次(在我的foreach循环中),我应该对服务器发出6个异步请求。但是在这种情况下,ajax调用是同步调用的,而不是异步调用的。有人知道为什么会这样吗? 问题答案: 好,谢谢。经过几个小时的分析和反思,我意识到了为什么该脚本会同步运行:我打开script.php文件,并注意到了这一点以及该文件的开头: 因此,我对使用会话的php脚本进行了并行ajax调

  • 我正在尝试为一些网站检索超文本标记语言。我正在使用PHPfile_get_contents它运行得非常好,但是很慢,而且有点有限,所以我决定试试Guzzes。不幸的是,我发现很难阻止Guzzes抛出异常,即使使用他们记录的异常处理。我的代码非常简单: 我不断得到以下错误: GuzzleHttp\Exception\ConnectException cURL错误28:无法连接到acme.biz端口8

  • Spring MVC 3.2开始引入了基于Servlet 3的异步请求处理。相比以前,控制器方法已经不一定需要返回一个值,而是可以返回一个java.util.concurrent.Callable的对象,并通过Spring MVC所管理的线程来产生返回值。与此同时,Servlet容器的主线程则可以退出并释放其资源了,同时也允许容器去处理其他的请求。通过一个TaskExecutor,Spring M

  • 问题内容: 我尝试了python 请求库文档中提供的示例。 使用,我得到了响应代码,但是我想获得所请求的每个页面的内容。例如,这不起作用: 问题答案: 注意 下面的答案是不适用于请求v0.13.0 +。编写此问题后,异步功能已移至。但是,你可以将其替换为下面的内容,它应该可以工作。 我已经留下了这个答案,以反映原始问题,即有关使用请求的问题。 要异步执行多个任务,你必须: 为每个对象定义一个函数(