在单独的进程中运行PHP更长的时间

时间:2016-09-04 19:33:38

标签: php performance laravel csv

我有一个目录,其中可以包含CSV文件,这些文件来自我需要导入数据库的服务。这些CSV文件各为1000行,可以是10到150个文件。

我想将所有这些CSV文件的数据插入数据库。问题是PHP由于超时问题而死亡,因为即使我使用set_time_limit(0),服务器(siteground.com)也会施加限制。这是代码:

// just in case even though console script should not have problem
ini_set('memory_limit', '-1');
ini_set('max_input_time', '-1');
ini_set('max_execution_time', '0');
set_time_limit(0);
ignore_user_abort(1);
///////////////////////////////////////////////////////////////////

function getRow()
{
    $files = glob('someFolder/*.csv');

    foreach ($files as $csvFile) {
        $fh = fopen($csvFile, 'r');

        $count = 0;
        while ($row = fgetcsv($fh)) {
            $count++;

            // skip header
            if ($count === 1) {
                continue;
            }

            // make sure count of header and actual row is same
            if (count($this->headerRow) !== count($row)) {
                continue;
            }

            $rowWithHeader = array_combine($this->headerRow, $row);

            yield $rowWithHeader;
        }
    }
}

foreach(getRow() as $row) {
   // fix row
   // now insert in database
}

这实际上是一个贯穿artisan的命令(我正在使用Laravel)。我知道CLI没有时间限制,但由于某些原因,并非所有CSV文件都会被导入,并且流程会在特定时间点结束。

所以我的问题是有没有办法为目录中的每个CSV文件调用单独的PHP进程?或者其他一些方法,这样我就可以导入所有CSV文件而不会出现任何问题,如PHP的generator,

3 个答案:

答案 0 :(得分:1)

你可以做一些bash魔法。重构您的脚本,以便它只处理一个文件。要处理的文件是脚本的参数,使用$argv访问它。

<?php
// just in case even though console script should not have problem
ini_set('memory_limit', '-1');
ini_set('max_input_time', '-1');
ini_set('max_execution_time', '0');
set_time_limit(0);
ignore_user_abort(1);
$file = $argv[1]; // file is the first and only argument to the script
///////////////////////////////////////////////////////////////////

function getRow($csvFile)
{
    $fh = fopen($csvFile, 'r');

    $count = 0;
    while ($row = fgetcsv($fh)) {
        $count++;

        // skip header
        if ($count === 1) {
            continue;
        }

        // make sure count of header and actual row is same
        if (count($this->headerRow) !== count($row)) {
            continue;
        }

        $rowWithHeader = array_combine($this->headerRow, $row);

        yield $rowWithHeader;
    }
}

foreach(getRow($file) as $row) {
   // fix row
   // now insert in database
}

现在,像这样调用你的脚本:

for file in `ls /path/to/folder | grep csv`; do php /path/to/your/script.php /path/to/folder/$file; done

这将为您.csv

中的每个/path/to/folder文件执行脚本

答案 1 :(得分:0)

最好的方法是每个php进程处理有限数量的文件。例如,您可以从10开始(计算一些文件经验)文件,处理它们,标记为已删除(移动到包含已处理文件的文件夹)并停止该过程。之后开始一个新进程导入另外10个文件,依此类推。在Laravel中,您可以说如果另一个进程已经运行,则不会为特定命令启动多个进程。 Laravel的命令如下:

$schedule->command("your job")->everyMinute()->withoutOverlapping();

如果您使用这种方法,您可以确保所有文件将在特定时间内处理,并且不会消耗太多资源来杀死。

答案 2 :(得分:0)

如果您的托管服务提供商允许cron作业,则他们没有超时限制。

此外,他们应该比手动调用重型和长期任务的函数更适合这项工作,因为如果多次调用该方法,这可能会造成巨大的问题。