5

我有一个脚本,当放在计时器上时,它会逐渐变慢。这相当简单,因为它所做的只是读取一行,检查它然后将其添加到数据库中,然后继续下一行。

这是它的输出逐渐变得更糟:

Record: #1,001 Memory: 1,355,360kb taking 1.84s
Record: #1,001 Memory: 1,355,360kb taking 1.84s
Record: #2,002 Memory: 1,355,192kb taking 2.12s
Record: #3,003 Memory: 1,355,192kb taking 2.39s
Record: #4,004 Memory: 1,355,192kb taking 2.65s
Record: #5,005 Memory: 1,355,200kb taking 2.94s
Record: #6,006 Memory: 1,355,376kb taking 3.28s
Record: #7,007 Memory: 1,355,176kb taking 3.56s
Record: #8,008 Memory: 1,355,408kb taking 3.81s
Record: #9,009 Memory: 1,355,464kb taking 4.07s
Record: #10,010 Memory: 1,355,392kb taking 4.32s
Record: #11,011 Memory: 1,355,352kb taking 4.63s
Record: #12,012 Memory: 1,355,376kb taking 4.90s
Record: #13,013 Memory: 1,355,200kb taking 5.14s
Record: #14,014 Memory: 1,355,184kb taking 5.43s
Record: #15,015 Memory: 1,355,344kb taking 5.72s

不幸的是,该文件大约为 20gb,所以当整个文件以增加的速度读取时,我可能已经死了。代码(主要)在下面,但我怀疑它与 fgets() 有关,但我不确定是什么。

    $handle = fopen ($import_file, 'r');

    while ($line = fgets ($handle))
    {
        $data = json_decode ($line);

        save_record ($data, $line);
    }

提前致谢!

编辑:

注释掉 'save_record ($data, $line);' 似乎什么都不做。

4

4 回答 4

1

有时最好使用系统命令来读取这些大文件。我遇到了类似的事情,这是我使用的一个小技巧:

$lines = exec("wc -l $filename");
for($i=1; $i <= $lines; $i++) {
   $line = exec('sed \''.$i.'!d\' '.$filename);

   // do what you want with the record here
}

对于无法信任的文件,我不建议这样做,但它运行速度很快,因为它使用系统一次提取一条记录。希望这可以帮助。

于 2010-08-17T23:24:39.420 回答
0

好吧,性能问题。显然,某些东西在不应该的时候会变成二次方,或者更重要的是,应该是恒定时间的东西似乎与迄今为止处理的记录数量呈线性关系。第一个问题是显示问题的最小代码片段是什么。我想知道当您注释掉除逐行读取文件之外的所有内容时,您是否会遇到相同的问题行为。如果是这样,那么您将需要一种没有该问题的语言。(有很多。)无论如何,一旦你看到预期的时间特征,就一个接一个地添加语句,直到你的时间变得混乱,你就会发现问题。

您使用了某些东西或其他东西来获取时间。通过单独执行它们 15000 次左右来确保它们不会导致问题。

于 2010-08-17T11:33:40.550 回答
0

http://php.net/manual/en/function.fgets.php

根据 Leigh Purdie 的评论,带有fgets. 如果你的 JSON 对象比他的测试线大,你可能会更快地达到极限

使用http://php.net/manual/en/function.stream-get-line.php并指定长度限制

于 2010-08-15T10:34:39.093 回答
0

我在试图找到一种方法让我更快地通过 96G 文本文件时发现了这个问题。我最初写的脚本花了 15 个小时才达到 0.1%...

我已经尝试了这里建议的一些解决方案,使用 stream_get_line、fgets 和 exec 进行 sed。我最终采用了一种不同的方法,我认为我会与其他人分享这个问题。

拆分文件!:-)

在我的 freebsd 机器上(也存在于 linux 和其他机器上)我有一个名为“split”的命令行实用程序。

用法:split [-l line_count] [-a suffix_length] [file [prefix]]
       split -b byte_count[K|k|M|m|G|g] [-a suffix_length] [文件[前缀]]
       split -n chunk_count [-a suffix_length] [文件[前缀]]
       拆分 -p 模式 [-a suffix_length] [文件 [前缀]]

所以我跑了:

拆分 -l 25000 -a 3 /data/var/myfile.log /data/var/myfile-log/

然后我在 /data/var/myfile-log/ 目录中得到了 5608 个文件,然后可以使用以下命令一次处理一个文件:

php -f do-some-work.php /data/var/myfile-log/*
于 2011-04-05T12:45:10.833 回答