PHP通过巨大的文本文件循环很慢,可以改进一下吗


PHP looping through huge text file is very slow, can you improve?

文本文件(实际上是.dat)中包含的数据如下:

LIN*1234*UP*abcde*33*0*EA
LIN*5678*UP*fghij*33*0*EA
LIN*9101*UP*klmno*33*23*EA

实际上在这个文件中有超过50万行这样的行。

这是我现在使用的:

//retrieve file once        
$file = file_get_contents('/data.dat'); 
$file = explode('LIN', $file);
    ...some code
foreach ($list as $item) { //an array containing 10 items
     foreach($file as $line) { //checking if these items are on huge list
         $info = explode('*', $line);
         if ($line[3] == $item[0]) {
             ...do stuff...                     
             break; //stop checking if found
          }
      }         
 }

问题是它运行得太慢了——每次迭代大约1.5秒。我单独确认了这不是"……"做的东西…这影响了速度。相反,它是搜索正确的项目。

我怎样才能加快速度?谢谢你。

如果每个条目都在自己的行上,而不是将整个内容加载到内存中,使用fgets()可能会更好:

$f = fopen('text.txt', 'rt');
while (!feof($f)) {
    $line = rtrim(fgets($f), "'r'n");
    $info = explode('*', $line);
    // etc.
}
fclose($f);

PHP文件流是缓冲的(~8kB),所以在性能方面应该是不错的。

另一部分逻辑可以这样重写(而不是多次迭代文件):

if (in_array($info[3], $items)) // look up $info[3] inside the array of 10 things

或者,如果$items被适当索引:

if (isset($items[$info[3]])) { ... }

file_get_contents将整个文件作为数组加载到内存中&然后你的代码对它起作用。从PHP fgets官方文档中改编这个示例代码应该会更好:

$handle = @fopen("test.txt", "r");
if ($handle) {
    while (($buffer = fgets($handle, 4096)) !== false) {
        $file_data = explode('LIN', $buffer);
        foreach($file_data as $line) {
            $info = explode('*', $line);
            $info = array_filter($info);
            if (!empty($info)) {
                echo '<pre>';
                print_r($info);
                echo '</pre>';
            }
        }         
    }
    if (!feof($handle)) {
        echo "Error: unexpected fgets() fail'n";
    }
    fclose($handle);
}
使用您的数据的上述代码的输出是:
Array
(
    [1] => 1234
    [2] => UP
    [3] => abcde
    [4] => 33
    [6] => EA
)
Array
(
    [1] => 5678
    [2] => UP
    [3] => fghij
    [4] => 33
    [6] => EA
)
Array
(
    [1] => 9101
    [2] => UP
    [3] => klmno
    [4] => 33
    [5] => 23
    [6] => EA
)

但是仍然不清楚你丢失的代码,因为那行声明:

foreach ($list as $item) { //an array containing 10 items

那似乎是另一个真正的瓶颈。

当您执行file_get_contents时,它会将内容加载到内存中,因此您只能想象该进程可能会占用多少资源。更不用说你还有一个嵌套循环,那就是(O)n^2

如果可能的话,您可以拆分文件或使用fopen, fgetsfclose逐行读取它们。

如果我是你,如果我真的需要速度,我会使用C++Go等其他语言。