如何重构一个长时间运行的PHP进程,以便不会超时

时间:2014-05-21 13:10:01

标签: javascript php ajax

我有一个简单的javascript函数:

$(document).ready(function(){
    var request = $.ajax({
        url: "read_images.php",
        type: "GET",
        dataType: "html"
    });
    request.done(function(msg) {
        $("#mybox").html(msg);
        document.getElementById('message').innerHTML = '';
    });
    request.fail(function(jqXHR, textStatus) {
        alert( "Request failed: " + textStatus );
    });
});

它调用的PHP脚本循环文件夹的内容,运行一些检查,并返回响应。脚本如下:

//Get all Images from server, store in variable
$server_images = scandir('../images/original');

//Remove first 3 elements, which are not correct
array_shift($server_images);
array_shift($server_images);
array_shift($server_images);

$j = 0;
for($i=0;$i<count($server_images) && $i<3000;$i++) {
     $server_image = $server_images[$i];

    //Make sure that the server image does not have a php extension
    if(!preg_match('/.php/',$server_image)) {

    //Select products_id and name from table where the image name is equal to server image name
    $query = "SELECT `name`
            FROM `images`
            WHERE `name` = '$server_image'";
    $mro_images = $db->query($query);
    $mro_images_row = $mro_images->fetch();
    $mro_image = $mro_images_row['name'];

    //If no results are found
    if(empty($mro_image)) {
        $images[$j] = $server_image;
        $j++;
    }
}
}

如果循环限制为2000次迭代,但是如果我尝试执行例如结果是3000次迭代:

HTTP/1.1 500 Internal Server Error 31234ms

我已尝试增加php执行限制,但在与我的主持人联系后,这并没有任何效果:

  

不幸的是,在我们的环境中,我们没有办法将负载均衡器超时时间延长超过30秒

因此:如何重构此代码以避免达到执行时间限制?

3 个答案:

答案 0 :(得分:2)

如果一切都适用于2000次迭代3000次迭代,请尝试增加时间限制以允许php执行更长时间。但在正常情况下,这不是一个好主意。确保你知道自己在做什么,并有充分的理由增加执行时间。

set_time_limit ( 60 );

http://www.php.net/manual/en/function.set-time-limit.php

这也可能是因为脚本耗尽了内存量。在其中创建一个包含phpinfo函数的文件,然后检查memory_limit的值。

<?php phpinfo(); ?>

然后你可以通过htaccess文件增加限制。但是再次确保您希望脚本消耗更多内存。小心。

ini_set('memory_limit', '128M'); #change 128 to suit your needs

答案 1 :(得分:1)

以下代码表示要遵循的基本逻辑。它不是经过测试的代码,不应被视为代码示例

使用 javascript 循环

而不是让慢速进程变慢 - 编写JavaScript以在循环中请求更小的数据块。

即。 js可以使用while循环:

$(document).ready(function(){
    var done = false,
        offset = 0,
        limit = 20;

    while (!done) {
        var url = "read_images.php?offset=" + offset + "&limit=" + limit;

        $.ajax({
            async: false,
            url: url
        }).done(function(response) {

            if (response.processed !== limit) {
                // asked to process 20, only processed <=19 - there aren't any more
                done = true;
            }

            offset += response.processed;
            $("#mybox").html("Processed total of " + offset + " records");

        }).fail(function(jqXHR, textStatus) {

            $("#mybox").html("Error after processing " + offset + " records. Error: " textStatus);

            done = true;
        });
    }

});

请注意,在上面的示例中,强制ajax调用是同步的。通常您不想这样做,但在这个示例中,它更容易编写,并且可能更容易理解。

每个 php 请求执行固定数量的工作

php代码还需要修改以期望并使用传递的get参数:

$stuff = scandir('../images/original');

$offset = $_GET['offset'];
$limit = $_GET['limit'];

$server_images = array_slice($stuff, $offset, $limit);

foreach($server_images as $server_image) {
    ...
}
...

$response = array(
    'processed' => count($server_images),
    'message' => 'All is right with the world'
);

header('Content-Type: application/json');
echo json_encode($response);
die;

通过这种方式,给定的php请求需要处理的工作量是固定的,因为要处理的数据总量增长(假设目录中的文件数量不会增长到不切实际的数字)。 / p>

答案 2 :(得分:0)

您的计数($ server_images)可能导致无限循环。

如果count()返回0,则for循环将永远不会结束。所以你需要先检查一下。

//Get all Images from server, store in variable
$server_images = scandir('../images/original');

//Remove first 3 elements, which are not correct
array_shift($server_images);
array_shift($server_images);
array_shift($server_images);

$j = 0;

if(count($server_images) > 0){    
    for($i=0;$i<count($server_images) && $i<3000;$i++) {
      //Do something
    }
}