php 想法来加速 18000+ 调用的脚本

问题描述 投票:0回答:3

我有一个可以进行几次调用的脚本。第一个调用获取键和哈希码的数组。然后它进入 foreach 并调用第二个 API,该 API 将返回一个项目列表,然后将其传递到第二个 foreach 循环,该循环处理该数据并将其发布到 MySQL 数据库。

运行脚本需要11个小时。我很感激有关如何加快速度的想法。我研究过多重处理,但我所看到的一切都表明发出网络请求是一个坏主意。欢迎任何想法或链接。

ini_set('max_execution_time', 60000);
date_default_timezone_set('UTC');
$time = date('Y-m-d');
echo $time;
$time_start = microtime(true);

$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, 'https://zkillboard.com/api/history/20170816/');
$result = curl_exec($ch);
curl_close($ch);
$obj = json_decode($result, true);
$holder = [];
$i = 0;
$urls = [];
foreach ($obj as $key => $item) {
    $urls[] = ['url' => "https://esi.evetech.net/dev/killmails/{$key}/{$item}/"];
}

$x = 0;
$limit = 15;
$urls = array_slice($urls,0,5);
//foreach (array_chunk($urls, 5, true) as $urlchunk) {
foreach ($urls as $urlchunk) {

        $x ++;
        $aURLs = $urlchunk; // array of URLs
        $mh = curl_multi_init(); // init the curl Multi

        $aCurlHandles = array(); // create an array for the individual curl handles

        foreach ($aURLs as $id => $url) { //add the handles for each url

//            $ch = curl_setup($url);
            $ch = curl_init(); // init curl, and then setup your options
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // returns the result - very important
            curl_setopt($ch, CURLOPT_HEADER, 0); // no headers in the output

            $aCurlHandles[$url] = $ch;
            curl_multi_add_handle($mh, $ch);
        }

        $active = null;
        //execute the handles
        do {
            $mrc = curl_multi_exec($mh, $active);

        } while ($mrc == CURLM_CALL_MULTI_PERFORM);

        while ($active && $mrc == CURLM_OK) {
            $mrc = curl_multi_exec($mh, $active);
            if (curl_multi_select($mh) != -1) {
                do {
                    $mrc = curl_multi_exec($mh, $active);
                } while ($mrc == CURLM_CALL_MULTI_PERFORM);
            }
        }

        /* This is the relevant bit */
        // iterate through the handles and get your content
        foreach ($aCurlHandles as $url => $ch) {
            $html = curl_multi_getcontent($ch); // get the content
            $obj1 = json_decode($html, true);
            $data = str_replace("{", "[", $obj1['victim']);
            $data2 = str_replace("}", "]", $data);

            foreach ($data2['items'] as $value) {
                if (!empty($value['quantity_destroyed'])) {
                    $holder[] = [
                        'item' => $value['item_type_id'],
                        'qty' => $value['quantity_destroyed'],
                        'date' => $time
                    ];
                }
                curl_multi_remove_handle($mh, $ch); // remove the handle (assuming  you are done with it);
            }
            /* End of the relevant bit */

            curl_multi_close($mh); // close the curl multi handler
        }

}
$servername = "localhost";
$username = "username";
$password = "password";
$conn = new mysqli($servername, 'root', '', 'eve');
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully<br>";
$i = 0;
foreach ($holder as $item) {

    $i++;
    $itemCheck = mysqli_query($conn, "SELECT * FROM item_temp WHERE itemid ={$item['item']} AND dates='{$item['date']}'");
    $row = mysqli_fetch_array($itemCheck, MYSQLI_ASSOC);
    if (!empty($row)) {
        $qty = $row['qty'] + $item['qty'];
        $kills = $row['kills'] + 1;
        $sql = "UPDATE item_temp SET qty='{$qty}' ,kills='{$kills}'  WHERE itemid={$item['item']} AND dates='{$item['date']}'";
        if ($conn->query($sql) === TRUE) {
        } else {
            echo "Error updating record: " . $conn->error;
        }
    } else {
        $sql = "INSERT INTO item_temp (itemid, qty, kills, dates)VALUES ('{$item['item']}', '{$item['qty']}', '1', '$time')";
        if ($conn->query($sql) === TRUE) {

        } else {
            echo "Error: " . $sql . "<br>" . $conn->error;
        }

    }
}
$time_end = microtime(true);
$execution_time = ($time_end - $time_start) / 60;
echo '<b>Total Execution Time:</b> ' . $execution_time . ' Mins';
echo '<b>'. $x;

代码已更新,显示

curl_multi
的运行速度大致相同。我不确定我是否以正确的方式使用它。

php curl optimization
3个回答
4
投票

目前,每个新请求仅在前一个请求完成后才会发送。您可以尝试使用 curl_multi_* 操作并行发送多个请求。 这是基于您的鳕鱼的示例

$time_start = microtime(true);

$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_URL, 'https://zkillboard.com/api/history/20170816/');
$result = curl_exec($ch);
curl_close($ch);
$obj = json_decode($result, true);
$holder = [];
$i = 0;
$urls = [];
foreach ($obj as $key => $item) {
    $urls[] = "https://esi.evetech.net/dev/killmails/{$key}/{$item}/";
}

$urls = array_slice($urls,0,20); // only first 20 for testing purposes

$mh = curl_multi_init(); // init the curl Multi);
$aCurlHandles = array(); // create an array for the individual curl handles

foreach ($urls as $urlchunk) {
        $ch = curl_init(); // init curl, and then setup your options
        curl_setopt($ch, CURLOPT_URL, $urlchunk);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // returns the result - very important
        curl_setopt($ch, CURLOPT_HEADER, 0); // no headers in the output

        $aCurlHandles[] = $ch;
        curl_multi_add_handle($mh, $ch);
}
$active = null;
//execute the handles
do {
    $mrc = curl_multi_exec($mh, $active);

} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    $mrc = curl_multi_exec($mh, $active);
    if (curl_multi_select($mh) != -1) {
        do {
            $mrc = curl_multi_exec($mh, $active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
}


/* This is the relevant bit */
// iterate through the handles and get your content
foreach ($aCurlHandles as $ch) {
    $html = curl_multi_getcontent($ch); // get the content
    $obj1 = json_decode($html, true);
    $holder[]= $obj1['killmail_time'];
    curl_multi_remove_handle($mh, $ch); // remove the handle (assuming  you are done with it);
}
curl_multi_close($mh); // close the curl multi handler
echo "multi_exec approach \n";
var_dump(sizeof($holder));
echo "\n";
var_dump(array_pop($holder));
echo "\nIt took: " . (microtime(true) - $time_start);

$time_start = microtime(true);
$holder = [];
foreach ($urls as $urlchunk) {
    $ch1 = curl_init();
    curl_setopt($ch1, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch1, CURLOPT_URL, $urlchunk);
    $result1 = curl_exec($ch1);
    curl_close($ch1);
    $holder[] = json_decode($result1, true)['killmail_time'];
}
echo "\n\nsequential approach \n";
var_dump(sizeof($holder));
echo "\n";
var_dump(array_pop($holder));
echo "\nIt took: " . (microtime(true) - $time_start);

小心,不要尝试并行发送所有请求(您提到的链接为 14480):您最好不要对 API 进行 DoS,同意吗?


0
投票
  • 不要使用 SELECT *,因为通过它可以避免使用可能存在的索引。
  • 使用索引(返回第1点)
  • 如果可能的话使用 IN (...) 可能会破坏你的逻辑?
  • 使用事务进行更新/插入?您的桌子上有锁问题吗?如果是这样,这将有助于打破流程的流程,并且您可以更好地控制您尝试建立的内容;根据手头的信息很难说。

-1
投票

想法:

如果您不使用 PHP7,您应该考虑升级到此版本的 PHP。核心(模块)本身比旧版本至少快 55%

© www.soinside.com 2019 - 2024. All rights reserved.