PHP 从 JSON 获取数据并更新 CSV 文件的脚本,cpu 使用率高

PHP script that gets data from JSON and updates CSV files, high cpu usage

我制作了这个 PHP 脚本,它从 JSON 文件中获取数据,然后在多个 CSV 文件的底部编辑或添加一行。 该脚本每 60 秒运行一次 cronjob,并且在 运行 时占用大量 CPU。我不是专家,我可能需要一些技巧来优化它,甚至改变它的工作方式以获得更好的性能。 感谢任何帮助

//get data from json
$coins = 'BTC,ETH,BNB,XRP,USDT,DOT';
$url = 'https://apilink'.$coins;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
$stats = json_decode($result, true);
curl_close($ch);

$timeupd = date('d/m/Y H:i:s');

//FIRST COIN
$date = $stats[0]['price_date'];
$createDate = new DateTime($date);
$date = $createDate->format('Y-m-d');

$cap = $stats[0]['market_cap'];
$high = $stats[0]['high'];
$daypc = number_format((float)$stats[0]['1d']['price_change_pct'] * 100, 2, '.', '');
$weekpc = number_format((float)$stats[0]['7d']['price_change_pct'] * 100, 2, '.', '');
$adjclose = $stats[0]['price'];
$volume = $stats[0]['1d']['volume'];
$monthpc = number_format((float)$stats[0]['30d']['price_change_pct'] * 100, 2, '.', '');
$yearpc = number_format((float)$stats[0]['365d']['price_change_pct'] * 100, 2, '.', '');
$ytdpc = number_format((float)$stats[0]['ytd']['price_change_pct'] * 100, 2, '.', '');

//create array
$array = array($date, $cap, $high, $daypc, $weekpc, $adjclose, $volume, $monthpc, $yearpc, $ytdpc, $timeupd);

//get last row from csv file
$rows = file('/firstcoin.csv');
$last_row = array_pop($rows);
$data = str_getcsv($last_row);

//add new line or modify it
if($date == $data[0] && !empty($stats[0]['price'])){
    $f = '/firstcoin.csv';
    $rows = file($f);
    array_pop($rows);                       // remove final element/row from $array
    file_put_contents($f, implode($rows));  // convert back to string and overwrite file
    $handle = fopen("/firstcoin.csv", "a");
    fputcsv($handle, $array);
    fclose($handle);
} elseif($date != $data[0] && !empty($stats[0]['price'])) {
    $handle = fopen("/firstcoin.csv", "a");
    fputcsv($handle, $array);
    fclose($handle);
} else {
    echo 'EMPTY JSON RESPONSE FOR FIRST COIN';
}

//SECOND COIN
//....other csv

//THIRD COIN
//....other csv

//ETC

您至少将整个文件读入内存一次,然后在第一种情况下将整个文件写回磁盘。这非常昂贵,而且随着文件的增长,情况会变得更糟。由于您只需要读取和写入文件末尾,因此您应该想办法只读取最后一行,可选择删除它,然后将新行写入文件末尾。

这是一个概念验证,您需要仔细测试这种技术,以确保它适用于您系统上的行尾。

<?php
//get last row from csv file
$handle = fopen('/firstcoin.csv', 'a+');

$data = getLastCsvLine($handle, $lastLineOffset);

//add new line or modify it
if($date == $data[0] && !empty($stats[0]['price'])){
    /*
     * Remove last line from the file
     * getLastCsvLine will set the file pointer to the beginning of the line,
     * so we can just truncate from there then add our line
     */
    ftruncate($handle, $lastLineOffset);
    fputcsv($handle, $array);
} elseif($date != $data[0] && !empty($stats[0]['price'])) {
    fputcsv($handle, $array);
} else {
    echo 'EMPTY JSON RESPONSE FOR FIRST COIN';
}

fclose($handle);

/**
 * Get the last CSV line in a file
 *
 * @param $fileHandle
 * @return array|false
 */
function getLastCsvLine($fileHandle, &$lastLineOffset)
{
    // Set the initial reverse offset
    $cursor = -1;

    // Set the file pointer to the end of the file
    fseek($fileHandle, $cursor, SEEK_END);

    // Rewind past any newlines at the end of the file
    do
    {
        $char = fgetc($fileHandle);
        fseek($fileHandle, --$cursor, SEEK_END);
    } while( $char === "\n" || $char === "\r" );

    // Read backwards until we hit the next newline or the beginning of the file
    do
    {
        // Step backwards one byte
        fseek($fileHandle, --$cursor, SEEK_END);

        // Get the current char
        $char = fgetc($fileHandle);

        // Test to see if it is a newline char
        $foundLineStart = ( $char === false || $char === "\n" || $char === "\r" );
    } while (!$foundLineStart);

    // Set the last line offset var and seek to the offset
    $lastLineOffset = ftell($fileHandle);

    // Return the data for the line
    return fgetcsv($fileHandle);
}