多线程 Curl 无法处理大量并发 URL?

5
我需要同时调用大量的API。我试图通过多线程 curl 来实现这一点,但是当我传入很多 URL 时,它似乎无法正确获取所有 API 的结果(有些会出错;我认为这是超时问题?)。每次最多只能传递 50 个 URL,大约在传递 100 个 URL 时就会出现问题。因此,我不得不实现逻辑来分块处理我要同时调用的 URL。
问题: 1. 是什么导致了我的 curl 问题? 2. 在 curl 中是否有设置可以告诉它等待更长时间以获取响应 - 以防我的问题与超时有关? 3. 在我的服务器 / php.ini 中是否有可以配置以提高脚本性能的选项?
以下是脚本代码:
function multithreaded_curl(array $urls, $concurrent_urls = 50)
    {
        // Data to be returned
        $total_results = array();

        // Chunk the URLs
        $chunked_urls = array_chunk($urls, $concurrent_urls);
        foreach ($chunked_urls as $chunked_url) {
            // Chunked results
            $results = array();

            // Array of cURL handles
            $curl_handles = array();

            // Multi-handle
            $mh = curl_multi_init();

            // Loop through $chunked_urls and create curl handles, then add them to the multi-handle
            foreach ($chunked_url as $k => $v) {
                $curl_handles[$k] = curl_init();

                curl_setopt($curl_handles[$k], CURLOPT_URL, $v);
                curl_setopt($curl_handles[$k], CURLOPT_HEADER, 0);
                curl_setopt($curl_handles[$k], CURLOPT_RETURNTRANSFER, 1);
                curl_setopt($curl_handles[$k], CURLOPT_SSL_VERIFYPEER, 0);

                curl_multi_add_handle($mh, $curl_handles[$k]);
            }

            // Execute the handles
            $running = NULL;
            do {
                curl_multi_exec($mh, $running);
            } while ($running > 0);

            // Get content and remove handles
            foreach ($curl_handles as $k => $v) {
                $results[$k] = json_decode(curl_multi_getcontent($v), TRUE);
                curl_multi_remove_handle($mh, $v);
            }

            // All done
            curl_multi_close($mh);

            // Combine results
            $total_results = array_merge($total_results, $results);
        }

        return $total_results;
    }

1 - 它不是多线程的 2 - 这可能是你达到了 PHP 超时,而不是实际的 curl 限制 - Daniel Stenberg
  1. curl_multi_exec 不是多线程的吗?
  2. 在调用此函数之前,我已经执行了 set_time_limit(0);
- StackOverflowNewbie
Golang会很有帮助:D 容易并发。 - Lansana Camara
可能会发生很多事情。在失败的句柄上调用curl_getinfo()curl_error()以获取更多详细信息。如果没有看到这些,我们甚至不知道它为什么会失败。除此之外,您可能会受到速率限制,一些服务器可能会阻止来自单个IP的超过x个同时连接,您的操作系统可能会遭受套接字或描述符耗尽的问题。如果您正在为API请求访问大量相同的主机,则更有效的方法是重复使用相同的cURL句柄,以利用服务器支持的保持活动连接。 - drew010
只需使用此库,https://github.com/marcushat/RollingCurlX。 - Shailesh
1个回答

3

关于Q1:正如已经评论的那样,有几种方法会导致该算法出现问题。首先,它可能会耗尽本地(句柄等)和远程(maxConnections、maxThreads等)资源。不要这样做。

关于Q2:你不需要这样做(请参见下文),但请在猜测错误之前获取错误响应。

关于Q3:是的,根据远程Web服务器的供应商,REMOTE Web服务器有几个选项(线程数量限制、最大连接数、每个客户端的最大连接数等)。如果这也是您的服务器,您可以调整这些以更好地适应您的需求,但首先应调整客户端算法。

总的来说,同时启动超过少量的连接并没有太多意义。连接重用更快,并且不会损坏您的本地句柄等,也不会对远程系统进行DOS攻击。唯一需要这样做的原因是服务器处理请求所需的时间比IO所需的时间长得多。

您是否检查过仅同时进行4个连接并重复使用它们时的速度?事实上,您正在为每个curl_handle[]填充一个单独的使用。创建IO对象需要时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接