首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >口吻异步请求不是真正的异步吗?

口吻异步请求不是真正的异步吗?
EN

Stack Overflow用户
提问于 2017-09-02 15:49:08
回答 1查看 25.7K关注 0票数 24

问题

我们正在尝试使用guzzle来执行并发异步请求。在浏览了一些资源(如 )之后,我们提出了一些下面共享的代码。然而,它并没有像预期的那样起作用。

看起来Guzzle是同步地而不是异步地执行这些请求。

期望值

只是为了测试目的,我们正在访问一个内部url,它可以进行5秒的睡眠。在并发性为10的情况下,我们预计所有10个请求最初都将被排队,并几乎同时发送到服务器,在那里它们将等待5秒,然后几乎所有这些请求都将几乎同时完成。这将使口香糖客户端从迭代器中获取10个新请求,等等。

代码

代码语言:javascript
复制
    $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();

实际结果

我们发现,在第一个请求完成之前,口香糖从来没有提出过第二个请求。诸若此类。

代码语言:javascript
复制
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 

OS /版本信息

  • Ubuntu
  • PHP/7.1.3
  • GuzzleHttp/6.2.1
  • 卷曲/7.47.0

问题可能是\GuzzleHttp\Promise\each_limit ..。它可能没有足够快地启动或解决承诺。我们可能不得不在外部欺骗tick

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-09-02 23:59:13

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

注意:它确定了从函数中使用的最佳处理程序。不过,它很可能最终会默认为curl_mutli_exec

这有什么重要的?它是负责同时跟踪和执行多个请求的底层处理程序。通过每次创建一个新的处理程序,您的请求都不会被正确地分组并一起运行。要想对此有更深入的了解,请深入了解文档

所以,你有两种方法来处理这个问题:

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

代码语言:javascript
复制
$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();

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

代码语言:javascript
复制
$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();
票数 21
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46015529

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档