PHP Conference Japan 2024

mysqli::poll

mysqli_poll

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

mysqli::poll -- mysqli_poll輪詢連線

描述

物件導向風格

public static mysqli::poll(
    ?array &$read,
    ?array &$error,
    array &$reject,
    int $seconds,
    int $microseconds = 0
): int|false

程序風格

mysqli_poll(
    ?array &$read,
    ?array &$error,
    array &$reject,
    int $seconds,
    int $microseconds = 0
): int|false

輪詢連線。此方法可以用作 static

注意:

僅在 mysqlnd 中可用。

參數

read

要檢查是否有未完成結果可以讀取的連線清單。

error

發生錯誤的連線清單,例如,查詢失敗或連線遺失。

reject

由於沒有執行可以輪詢結果的非同步查詢而遭到拒絕的連線清單。

seconds

最大等待秒數,必須為非負數。

microseconds

最大等待微秒數,必須為非負數。

傳回值

成功時傳回準備就緒的連線數,否則傳回 false

錯誤/例外

當沒有傳遞 readerror 引數時,會拋出 ValueError

變更日誌

版本 描述
8.3.0 當沒有傳遞 readerror 引數時,現在會拋出 ValueError 例外。

範例

範例 #1 mysqli_poll() 範例

<?php
$link1
= mysqli_connect();
$link1->query("SELECT 'test'", MYSQLI_ASYNC);
$all_links = array($link1);
$processed = 0;
do {
$links = $errors = $reject = array();
foreach (
$all_links as $link) {
$links[] = $errors[] = $reject[] = $link;
}
if (!
mysqli_poll($links, $errors, $reject, 1)) {
continue;
}
foreach (
$links as $link) {
if (
$result = $link->reap_async_query()) {
print_r($result->fetch_row());
if (
is_object($result))
mysqli_free_result($result);
} else die(
sprintf("MySQLi Error: %s", mysqli_error($link)));
$processed++;
}
} while (
$processed < count($all_links));
?>

上面的範例會輸出

Array
(
    [0] => test
)

參見

新增註解

使用者提供的註解 5 則註解

7
l_sanczyk at hotmail dot com
10 年前
您可以使用以下程式碼執行,例如,10 個同步查詢

$query = "SELECT `field1`, `field2` FROM `table` WHERE `field1`='something'";

$all_links = array();
for($i=0; $i<10; $i++) {
$link = mysqli_connect("your.mysql.server.here","your@user","pa$$w0rd",DataBase_Name");
$link->query($query, MYSQLI_ASYNC);
$all_links[] = $link;
}

$processed = 0;
do {
$links = $errors = $reject = array();
foreach ($all_links as $link) {
$links[] = $errors[] = $reject[] = $link;
}
if (!mysqli_poll($links, $errors, $reject, 1)) {
continue;
}
foreach ($links as $link) {
if ($result = $link->reap_async_query()) {
print_r($result->fetch_row());
if (is_object($result))
mysqli_free_result($result);
} else die(sprintf("MySQLi Error: %s", mysqli_error($link)));
$processed++;
}
} while ($processed < count($all_links));

注意:如果您收到「警告:mysqli::query() 預期參數 2 為 long,給定 string」,則您有 mysqlnd 安裝或設定問題。
3
shestero at meta dot ua
8 年前
有時不清楚連線「就緒」是什麼意思。是指查詢完成還是只有一些記錄準備好讀取?
是否可以使用非同步(非阻塞)和非緩衝的 SELECT 查詢?即使用 MYSQLI_ASYNC|MYSQLI_USE_RESULT

我希望在我的迴圈中使用一些類似輪詢的程式碼,其中有四個案例選項
1. 輪詢等待時間結束,但沒有結果集的記錄準備就緒。
2. 一或多個記錄準備好讀取(但查詢仍在執行)。
3. 查詢成功結束(完成;沒有更多記錄)。
4. 錯誤。

有可能嗎?

據我了解,如果目前沒有準備好的記錄,從非緩衝查詢中讀取記錄的操作是會阻塞的,而且沒有任何函式可以知道有多少記錄準備好了?
1
marcin dot wanat at gmail dot com
1 年前
值得注意的是,此文件中的範例會導致等待所有查詢執行完畢後,您才能收割結果。

5 年前,來自 php.net 的 bishop 發布了一個解決方案,可以讓您在執行後立即提取每個查詢的結果。但由於某些原因,這從未合併到 php 手冊中。

https://bugs.php.net/bug.php?id=70505

mysqli_poll 的文件建議在執行輪詢後迭代連結

foreach ($links as $link) {
if ($result = $link->reap_async_query()) {
print_r($result->fetch_row());
if (is_object($result))
mysqli_free_result($result);
} else die(sprintf("MySQLi Error: %s", mysqli_error($link)));
$processed++;
}

當您有多個執行時間不同的查詢時,這不是一個好的處理方式,因為 mysqli_reap_async_query() 會阻塞直到查詢完成,這與非同步輪詢的本質相悖。

一種處理多個執行時間不同的查詢的方法是對每個修改過的陣列執行收割(reaping)函數。

$count = mysqli_poll($read, $error, $reject, 1);
if (0 < $count) {
array_walk($read, 'reap');
array_walk($error, 'reap');
array_walk($reject, 'reap');
}

function reap($link) {
$result = mysqli_reap_async_query($link);
if (is_object($result)) {
print_r($result->fetch_assoc()));
mysqli_free_result($result);
} else if (false !== $result) {
print_r($link);
} else {
die(mysqli_error($link));
}
}

這也處理了查詢為 CRUD 操作,且 reap_async_query 的結果不是結果物件的情況。
0
ekalashnikov at gmail dot com
7 年前
改進的使用輪詢檢查慢查詢的版本,
如果 mysqli 連線的 ID 與要終止它的 ID 相同,「KILL #ID」將無法運作,
因此您必須斷開與 mysqli 的連線,並使用新的連線再次連線才能
終止 #ID。
<?php
// 慢速 SQL 查詢
$SelectSql = 'SELECT * FROM SLOW_QUERY';
$link = mysqli_connect('localhost','user','pass','database');
mysqli_query($SelectSql, MYSQLI_ASYNC);
$thread_id = mysqli_thread_id($link);
// 忽略使用者中止,以便我們可以終止查詢
ignore_user_abort(true);
$MaxTime = 5; // 秒
$Overtime = false;
$StartTime = time();
do
{
// 輪詢 MySQL
$links = $errors = $reject = array($link);
$poll = mysqli_poll($links, $errors, $reject, 0, 500000);
// 檢查連線是否中止且查詢是否已終止
if (connection_aborted()) {
$link_new = mysqli_connect('localhost','user','pass','database');
mysqli_kill($link_new, $thread_id);
$kill = mysqli_kill($link_new, $thread_id);
if (
$kill)
{
die();
}
}
$EndTime = time();
// 檢查是否超時,如果偵測到超時則終止
if ($EndTime - $StartTime > $MaxTime)
{
$link_new = mysqli_connect('localhost','user','pass','database');
mysqli_kill($link_new, $thread_id);
$Overtime = true;
echo
'Error: Query took over '.$Overtime.'.';
}
} while (!
$poll && $Overtime == false);
?>
0
ekalashnikov at gmail dot com
7 年前
這是如何使用輪詢測試和終止慢查詢的方法。

<?php
// 慢速 SQL 查詢
$SelectSql = 'SELECT * FROM SLOW_QUERY';
$link = mysqli_connect('localhost','user','pass','database');
mysqli_query($SelectSql, MYSQLI_ASYNC);
$thread_id = mysqli_thread_id($link);
// 忽略使用者中止,以便我們可以終止查詢
ignore_user_abort(true);
$MaxTime = 5; // 秒
$Overtime = false;
$StartTime = time();
do
{
// 輪詢 MySQL
$links = $errors = $reject = array($link);
$poll = mysqli_poll($links, $errors, $reject, 0, 500000);
// 檢查連線是否中止且查詢是否已終止
if (connection_aborted() && mysqli_kill($link, $thread_id)) {
die();
}
$EndTime = time();
// 檢查是否超時,如果偵測到超時則終止
if ($EndTime - $StartTime > $MaxTime)
{
mysqli_kill($link, $thread_id);
$Overtime = true;
echo
'Error: Query took over '.$Overtime.'.';
}
} while (!
$poll && $Overtime == false);
?>
To Top