加快18000多个通话的脚本的PHP创意

时间:2018-08-05 20:16:27

标签: php curl optimization

我有一个可以打几个电话的脚本。第一个调用获取键和哈希码的数组。然后进入一个foreach并调用第二个api,它将返回一个项目列表,该列表然后传递到与该数据一起使用的第二个foreach循环中并发布到mysql数据库中。运行脚本需要11个小时,我需要关于如何加快速度的想法,可以研究多重处理,但是我看到的一切都表明提出Web请求是一个老爸的主意。欢迎任何想法或链接。 这是代码

 <?php
/**
 * Created by PhpStorm.
 * User: shawn
 * Date: 7/28/2018
 * Time: 12:45 PM
 */
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正在以相同的速度运行,不确定我是否使用正确的方式

3 个答案:

答案 0 :(得分:3)

当前,每个新请求仅在上一个请求完成后才发送。您可以尝试与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):您最好不要使用DoS API,同意吗?

答案 1 :(得分:0)

  • 请勿使用SELECT *,因为这样可以避免使用可能存在的可能索引。
  • 使用指数(返回第1点)
  • 尽可能使用IN(...),也许会破坏您的逻辑?
  • 使用事务进行更新/插入吗?桌上有锁问题吗?如果是这样,这将有助于中断流程,并且您将对尝试建立的内容有更多的控制;眼前的信息很难说。

答案 2 :(得分:-1)

想法:

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