Ajax调用php进行csv文件操作挂起

时间:2012-07-30 11:24:25

标签: php ajax optimization

好的,我有一个按钮。按下它时会这样做:

的Javascript

$("#csv_dedupe").live("click", function(e) {
    file_name = 'C:\\server\\xampp\\htdocs\\Gene\\IMEXporter\\include\\files\\' + $("#IMEXp_import_var-uploadFile-file").val();
    $.post($_CFG_PROCESSORFILE, {"task": "csv_dupe", "file_name": file_name}, function(data) {
        alert(data);
    }, "json")
});

此ajax调用被发送到此:

PHP

class ColumnCompare {
    function __construct($column) {
        $this->column = $column;
    }

    function compare($a, $b) {
        if ($a[$this->column] == $b[$this->column]) {
            return 0;
        }
        return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
    }
}

if ($task == "csv_dupe") {
    $file_name = $_REQUEST["file_name"];

    // Hard-coded input
    $array_var = array();
    $sort_by_col = 9999;
    //Open csv file and dump contents
    if(($handler = fopen($file_name, "r")) !== FALSE) {
        while(($csv_handler = fgetcsv($handler, 0, ",")) !== FALSE) {
            $array_var[] = $csv_handler;
        }
    }
    fclose($handler);

    //copy original csv data array to be compared later
    $array_var2 = $array_var;

    //Find email column
    $new = array();
    $new = $array_var[0];
    $findme = 'email';
    $counter = 0;
    foreach($new as $key) {
        $pos = strpos($key, $findme);
        if($pos === false) {
            $counter++;
        }
        else {
            $sort_by_col = $counter;
        }
    }
    if($sort_by_col === 999) {
        echo 'COULD NOT FIND EMAIL COLUMN';
        return;
    }

    //Temporarily remove headers from array
    $headers = array_shift($array_var);
    // Create object for sorting by a particular column
    $obj = new ColumnCompare($sort_by_col);
    usort($array_var, array($obj, 'compare'));

    // Remove Duplicates from a coulmn
    array_unshift($array_var, $headers);
    $newArr = array();
    foreach ($array_var as $val) {
        $newArr[$val[$sort_by_col]] = $val;
    }
    $array_var = array_values($newArr);

    //Write CSV to standard output
    $sout = fopen($file_name, 'w');
    foreach ($array_var as $fields) {
        fputcsv($sout, $fields);
    }
    fclose($sout);

    //How many dupes were there?
    $number = count($array_var2) - count($array_var);    
    echo json_encode($number);
}

这个php从csv文件中获取所有数据。列和行并使用fgetcsv函数将所有数据分配给数组。现在我有代码在那里也通过单个列重复删除(查找并删除副本的副本)csv文件。保持整个数组的行和列结构完整。

唯一的问题是,即使它适用于我测试的10行左右的小文件,但它对25,000的文件不起作用。

现在在你说之前,我已经进入我的php.ini文件,并将max_input,filesize,max time running等更改为天文值,以确保php可以接受文件大小上升到999999999999999MB并运行其脚本的时间几百年。

我使用了包含25,000条记录的文件并执行该脚本。已经两个小时了,小提琴手仍然显示还没有发回http请求。有人可以给我一些方法,我可以优化我的服务器和我的代码吗?

我能够使用那些帮助我的用户的代码,这个用户在我发布的另一个问题上最初是如何做到的。我现在担心的是,即使我测试了它,我想知道如何让它在不到一分钟的时间内完成。 Excel可以在几秒内重复删除一百万条记录的列,为什么php不能这样做?

1 个答案:

答案 0 :(得分:0)

索菲,我认为你没有经验写这种类型的应用程序,因为IMO不是解决这个问题的方法。所以我会相应地说这个。

当你遇到这样的性能问题时,你真的需要二进制来解决问题,以了解发生了什么。因此,第1步是将PHP计时问题与AJAX分离,并简单了解为什么您的方法如此反应迟钝。使用本地安装的PHP-cgi执行此操作,甚至使用Web安装并发出标头('Context-Type:text / plain')并转储每个步骤的microtiming。 CSV读取需要多长时间,同样排序,然后是nodup,然后是写入?对于每次行数增加10倍的CSV文件大小,请执行此操作。

还要在每一步执行memory_get_usage()以查看如何扼杀内存。因为你的方法真的很糟糕,并且你可能通过达到配置的内存限制而错误 - phpinfo()会告诉你这些。

read,nodup和write都是o(N),但最好是o(NlogN),最坏的是o(N 2 )。您的排序也是每次比较调用PHP方法,因此

我不明白为什么你甚至在进行排序,因为你的nodup算法没有利用行被排序的事实。

(顺便说一句,排序也会对标题行进行内联排序,所以你需要在之前取消它,如果你还想这样做的话。)

您还需要考虑其他问题,例如

  • 使用原始参数作为文件名会使您容易受到攻击。最好修复相对于DOCROOT / Gene / IMEXporter / include的补丁,并对文件名强制执行一些语法。

  • 您需要考虑读取和重写大文件的原子性,作为对Web请求的响应 - 如果两个客户端同时发出请求,会发生什么。

  • 最后你将它与Excel进行比较,加载和保存Excel文件可能需要一些时间,并且Excel不必按比例缩放以同时响应10s或100s或用户。在事务系统中,您通常使用D / B后端进行此类操作,如果您使用Web界面来计算繁重的任务,则需要接受Apache(或等效服务器)硬内存和时序约束并切断您的algos并采取相应的方法。