curl_multi_select

(PHP 5, PHP 7, PHP 8)

curl_multi_select等待任何 curl_multi 连接上的活动

描述

curl_multi_select(CurlMultiHandle $multi_handle, float $timeout = 1.0): int

阻塞,直到任何 curl_multi 连接上都有活动。

参数

multi_handle

curl_multi_init() 返回的 cURL 多路复用句柄。

timeout

等待响应的时间(以秒为单位)。

返回值

成功时,返回描述符集中包含的描述符数量。如果任何描述符都没有活动,则这可能为 0。失败时,此函数将在选择失败时(来自底层选择系统调用)返回 -1。

变更日志

版本 描述
8.0.0 multi_handle 现在期望 CurlMultiHandle 实例;以前,期望的是 resource

参见

添加备注

用户贡献的备注 9 个备注

nevil85 at gmail dot com
10 年前
即使经过了如此多的发行版发布,在 PHP v5.5.9 和 libcurl v7.35.0 中,curl_multi_select 仍然返回 -1。这里唯一的解决方法是等待并像什么都没发生一样继续执行。您需要确定此处所需的“等待”时间。

在我的应用程序中,一个非常小的间隔,比如 usleep(1) 就可以工作。例如

<?php
// 当我们仍然处于活动状态时,执行 curl
$active = null;
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);

while (
$active && $mrc == CURLM_OK) {
// 等待任何 curl 连接上的活动
if (curl_multi_select($multi) == -1) {
usleep(1);
}

// 继续执行,直到 curl 准备好
// 向我们提供更多数据
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);
}
?>

在内部,php curl_multi_select 使用 libcurl curl_multi_fdset 函数,其 libcurl 文档指出
http://curl.haxx.se/libcurl/c/curl_multi_fdset.html

"当 libcurl 在 max_fd 中返回 -1 时,是因为 libcurl 目前正在执行一些您的应用程序无法使用套接字监控的操作,不幸的是,您无法确切知道当前操作何时使用 select() 完成。当 max_fd 返回 -1 时,您需要等待一段时间,然后继续执行并调用 curl_multi_perform。等待多长时间?我建议至少 100 毫秒,但您可能需要在自己的特定条件下测试一下,以找到合适的值。

在进行 select() 时,您应该使用 curl_multi_timeout 来确定等待操作的时间。"

在 PHP 实现 curl_multi_timeout() 之前,我们必须对我们的应用程序进行一些处理,并确定“等待”时间。
bishop at php dot net
5 年前
在 PHP 7.1.23 和 7.2.11 之前,如果 cURL 没有打开的文件描述符,curl_multi_select() 将返回 -1。从那时起,假设 libcurl 7.28 或更高版本,如果 cURL 没有打开的文件描述符,curl_multi_select() 将返回 0,如果发生错误,则返回 -1。

参见 https://bugs.php.net/bug.php?id=76480

这是一个 BC 冲突。参见 https://bugs.php.net/bug.php?id=77030
vigo dot von dot harrach at gmx dot de
12 年前
curl_multi_select($mh, $timeout) 只是在 curl_multi_exec() 返回 CURLM_CALL_MULTI_PERFORM 时阻塞 $timeout 秒。否则,它按预期工作,并阻塞,直到至少有一个连接完成或 $timeout 秒,以先发生者为准。

因此,curl_multi_exec() 应该始终被包装

<?php
function full_curl_multi_exec($mh, &$still_running) {
do {
$rv = curl_multi_exec($mh, $still_running);
} while (
$rv == CURLM_CALL_MULTI_PERFORM);
return
$rv;
}
?>

这样,“多路复用”处理的核心就变成了(为了简洁起见,忽略了错误处理)

<?php
full_curl_multi_exec
($mh, $still_running); // 启动请求
do { // “等待完成”循环
curl_multi_select($mh); // 非繁忙 (!) 等待状态更改
full_curl_multi_exec($mh, $still_running); // 获取新状态
while ($info = curl_multi_info_read($mh)) {
// 处理已完成的请求(例如 curl_multi_getcontent($info['handle']))
}
} while (
$still_running);
?>

请注意,在启动请求后,检索在后台进行 - 这是在 PHP 中进行并行处理的最佳方法之一。
public at grik dot net
16 年前
此函数会阻塞调用进程,直到 curl_multi 接口打开的任何连接都有活动,或者直到超时时间到期。
换句话说,它会等待打开的连接接收数据。

在内部,它使用“curl_multi_fdset()”获取套接字指针,并运行“select()”C 函数。
它在三种情况下返回
1. 在任何套接字上检测到活动;
2. 超时结束(第二个参数);
3. 进程收到任何信号(#man kill)。

该函数返回一个整数
* 如果检测到活动,它将返回一个数字,通常为 1。
我想,它返回具有活动连接的活动数量。
* 如果超时时间到期,它将返回 0
* 如果发生错误,它将返回 -1

感谢您的关注,希望这有帮助。
xxavalanchexx at gmail dot com
10 年前
根据 https://bugs.php.net/bug.php?id=61141:

在使用 libcurl 版本 7.24 或更高版本(对应于 PHP 5.3.10 或更高版本)的 Windows 设置中,您可能会发现它始终返回 -1。这显然不是严格意义上的错误:根据 libcurl 文档,如果 curl_multi_select 返回 -1,您应该添加自己的休眠。

例如
<?php
/* 设置 $mh */

$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);

while (
$active && $mrc == CURLM_OK) {
if (
curl_multi_select($mh) == -1) {
usleep(100);
}
do {
$mrc = curl_multi_exec($mh, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);
}

/* 关闭 $mh */
?>
匿名
10 年前
在 5.3.9+ 中,curl_multi_select 始终返回 -1。如果这是您的情况,只需等待一段时间,然后像什么都没发生一样继续。
<?php
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);

while (
$active && $mrc == CURLM_OK) {
// 检查结果并执行直到所有操作完成

if (curl_multi_select($multi) == -1) {
// 如果它返回 -1,等待一段时间,但继续前进!
usleep(100);
}

// 对返回值执行某些操作
while(($info = curl_multi_info_read($multi)) !== false){
if (
$info["result"] == CURLE_OK){
$content = curl_multi_getcontent($info["handle"]);
do_something($content);
}
}
do {
$mrc = curl_multi_exec($multi, $active);
} while (
$mrc == CURLM_CALL_MULTI_PERFORM);
}
?>
gib-o-master
2 年前
注意:`curl_multi_select` 的当前实现不会阻塞,也不会遵守超时参数(可能稍后会修复,在这种情况下只需删除 usleep 调用)

在这里,我想发布我关于如何正确使用此函数的有效/经过测试的示例

```
$running = 1;
while ($running)
{
# 执行请求
if ($a = curl_multi_exec($this->murl, $running)) {
throw BotError::text("curl_multi_exec[$a]: ".curl_multi_strerror($a));
}
# 检查是否完成
if (!$running) {
break;
}
# 等待活动
while (!$a)
{
if (($a = curl_multi_select($this->murl, $timeout)) < 0)
{
throw BotError::text(
($a = curl_multi_errno($this->murl))
? "curl_multi_select[$a]: ".curl_multi_strerror($a)
: '系统 select 失败'
);
}
usleep($timeout * 1000000);# 应该 <=1
}
}
```
Alex Palmer
11 年前
在 php 5.3.18+ 上,请注意 curl_multi_select() 可能永远返回 -1,直到您调用 curl_multi_exec()。
有关更多信息,请参见 https://bugs.php.net/bug.php?id=63411
匿名
14 年前
由于文档仍然缺乏,以下是如何使用该函数的示例。以下代码将继续检查所有活动线程,直到其中一个返回 HTTP 200 Ok 状态代码或简单地结束。成功后,它将返回有效的 URL。

<?php
$running
=null;
do {
curl_multi_exec($mh,$running);
$ready=curl_multi_select($mh); // 这将暂停循环
if($ready>0){
while(
$info=curl_multi_info_read($mh)){
$status=curl_getinfo($info['handle'],CURLINFO_HTTP_CODE);
if(
$status==200){
$successUrl=curl_getinfo($info['handle'],CURLINFO_EFFECTIVE_URL);
break
2;
}
}
}
} while (
$running>0 && $ready!=-1);
?>

对于 $ready 变量的问题是,它是在超时发生之前还是之后返回该值。根据我的测试,它似乎会立即返回该值,然后才会暂停执行。这是因为它始终是循环中第一次的零值,即使时间限制高达 10 秒。我原本预计它会等待,然后才会返回该值,因此这让我感到意外。

正如其他人所述,它似乎也没有返回句柄中的线程总数,而只返回当前活动线程的数量。
To Top