PHP Conference Japan 2024

curl_multi_select

(PHP 5, PHP 7, PHP 8)

curl_multi_select等待任何 cURL 多重控制代碼連線可以讀取或寫入

說明

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

封鎖腳本的執行,直到附加到 cURL 多重控制代碼的 cURL 控制代碼可以在下次呼叫 curl_multi_exec() 時取得進展,或者直到逾時(以先發生者為準)。

參數

multi_handle

curl_multi_init() 傳回的 cURL 多重控制代碼。

timeout

等待來自活動 cURL 多重控制代碼連線的回應時間,以秒為單位。

傳回值

成功時,會傳回描述元集中包含的活動描述元數量。如果任何描述元上沒有活動,則可能為 0。失敗時,此函式將在選取失敗時(來自底層的 select() 系統呼叫)傳回 -1

錯誤/例外

如果 timeout 小於 0 或大於 PHP_INT_MAX,則會擲回 ValueError

變更紀錄

版本 說明
8.4.0 如果 timeout 小於 0 或大於 PHP_INT_MAX,現在會擲回 ValueError
8.0.0 multi_handle 現在預期是 CurlMultiHandle 實例;先前,預期是 resource

參見

新增筆記

使用者提供的筆記 8 筆筆記

41
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 目前正在執行您的應用程式無法使用 socket 監控的某些操作,而且不幸的是,您無法確切知道何時使用 select() 完成目前的操作。當 max_fd 傳回 -1 時,您需要等待一段時間,然後再繼續並呼叫 curl_multi_perform。要等待多久?我建議至少 100 毫秒,但您可能需要在您自己的特定條件下測試以找到合適的值。

在執行 select() 時,您應該使用 curl_multi_timeout 來確定等待操作的時間。」

在 PHP 實作 curl_multi_timeout() 之前,我們必須在我們的應用程式中進行測試並確定「等待」。
3
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
16
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 中實現平行處理的較好方式之一。
10
public at grik dot net
16 年前
此函式會阻塞呼叫的程序,直到由 curl_multi 介面開啟的任何連線上有活動,或直到逾時期間結束。
換句話說,它會等待已開啟的連線接收到資料。

在內部,它會使用 "curl_multi_fdset()" 取得 socket 指標,並執行 "select()" C 函式。
它會在 3 種情況下返回
1. 在任何 socket 上偵測到活動;
2. 逾時已結束 (第二個參數);
3. 程序接收到任何訊號 (#man kill)。

此函式會返回一個整數
* 如果有活動,它會返回一個數字,通常是 1。
我認為,它會返回偵測到活動的連線數。
* 如果逾時過期,它會返回 0
* 如果發生錯誤,它會返回 -1

感謝您的關注,希望這有幫助。
4
xxavalanchexx at gmail dot com
10 年前
根據 https://bugs.php.net/bug.php?id=61141:

在使用 libcurl 版本 7.24 或更高版本的 Windows 設定 (這似乎對應於 PHP 5.3.10 或更高版本) 中,您可能會發現此函式總是返回 -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 */
?>
6
Anonymous
11 年前
在 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);
}
?>
1
gib-o-master
3 年前
注意:目前 `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)
: 'system select failed'
);
}
usleep($timeout * 1000000);# 應該 <=1
}
}
```
6
Alex Palmer
11 年前
在 php 5.3.18+ 版本中,請注意 curl_multi_select() 可能會永遠返回 -1,直到您呼叫 curl_multi_exec() 為止。
請參閱 https://bugs.php.net/bug.php?id=63411 以取得更多資訊。
To Top