PHP/Ajax 轮询进度


PHP/Ajax Polling Progress

我正在尝试实现 php 脚本循环的实时轮询,但到目前为止我的尝试没有运气。 这是我到目前为止所拥有的:

在表格提交时:

$.ajax({
data: $(this).serialize(),
success: showResponse,
url: 'process.php',
type: 'post'
});
function showResponse(){
$.ajax({
type: "GET",
url: "progress.php",
cache: false,
success: function(data) {
var response = $.parseJSON(data);
if (response.processing === true) {
console.log("Current Item: " + response.currentItem +
"Total Items: " + response.totalItems +
 "Percent Complete: " + response.percentComplete);
setTimeout(checkProgress, 1000);
});
}

在此过程中.php脚本:

session_start();
echo json_encode(array("processing" => true));
$totalItems = 10000000;
$_SESSION['totalItems'] = $totalItems;
$_SESSION['processing'] = true;
$_SESSION['error'] = false;
for ($i=0; $i <= $totalItems; $i++) {
$_SESSION['currentItem'] = $i;
$_SESSION['percentComplete'] = round(($i / $totalItems * 100));
}

在进行中的 php 脚本中:

session_start();
echo json_encode(array(
"processing" => $_SESSION['processing'],
"error" => $_SESSION['error'],
"currentItem" => $_SESSION['currentItem'],
"totalItems" => $_SESSION['totalItems'],
"percentComplete" => $_SESSION['percentComplete']
)
);

不知道我在这里出了什么问题,但它所做的只是在达到 100% 完成后循环。 任何建议将不胜感激!

编辑我在此过程中将上述内容更改为使用 apc.php:

apc_store('totalItems', $totalItems);
apc_store('processing', true);
apc_store('error', false);
apc_store('currentItem', $i);
apc_store('percentComplete', round(($i / $totalItems * 100)));

在进展中.php:

echo json_encode(array(
"processing" => apc_fetch('processing'),
"error" => apc_fetch('error'),
"currentItem" => apc_fetch('currentItem'),
"totalItems" => apc_fetch('totalItems'),
"percentComplete" => apc_fetch('percentComplete')
    )
);

仍然无法按照我希望它工作的方式正常工作,我做错了什么吗? 它只显示 false 值,直到脚本完成,并显示 100%,就像之前使用会话一样。 有什么想法吗?

会话信息是只能独占使用的资源,您尚未考虑到这一点。

具体来说,在默认设置下session_start会导致 PHP 在包含会话数据的文件上获取独占锁。在脚本退出或调用session_write_close之前,不会解锁此文件。

在您的示例中,process.php获取锁并开始工作。同时,progress.php尝试session_start()并且无法(由于锁定)。需要经过足够的时间才能完成并退出process.php(从而释放锁),然后才能满足进度信息请求。

您可以做出的一个小更改将立即生效,即从工作线程循环中调用session_write_closesession_start

for ($i=0; $i <= $totalItems; $i++) {
    session_start();
    $_SESSION['currentItem'] = $i;
    $_SESSION['percentComplete'] = round(($i / $totalItems * 100));
    session_write_close();
}

这将允许两个脚本轮流锁定会话存储文件,因此您将看到事情按预期工作。但是,性能会下降(这是处理会话存储文件的一种非常不礼貌的方式)。

如果你需要在现实世界中做这样的事情,那么有必要利用会话数据以外的其他东西来实现PHP脚本之间的这种信息交换(例如,像APC或memcached这样的内存缓存)。