【问题标题】:Looping queries to an API is really slow循环查询 API 真的很慢
【发布时间】:2017-03-19 22:19:28
【问题描述】:

我听说可以通过仅使用一个查询而不是对每个循环进行查询来循环 JSON 数据。任何想法如何从这段代码中做到这一点? 我真的需要这样做,因为成功加载页面最多需要 3 分钟..

* PHP *

<?php foreach ($return as $user) {
    $link = "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=$devkey&steamids=$user->SteamID";
    $json = file_get_contents($link);
    $decoding = json_decode($json);
    $avatar = $decoding->response->players[0]->avatar;
?>
<td id="addme"><img src="<?php echo $avatar; ?>" width="32" height="32"></td>
<td><?php echo $user->DisplayName; ?></td>
<td><?php echo $user->SteamID; ?>  <a href="http://steamcommunity.com/profiles/<?php echo $user->SteamID; ?>/" target="_blank"><span class="glyphicon glyphicon-new-window" id="gotosteamprofile"></span></a></td>
<td><?php
         $ipredc = substr($user->Address, 0, -6);
         echo $ipredc; ?></td>
<td><?php 
         $toconver = $user->ConnectedSeconds;
         $hours = floor($toconver / 3600);
         $mins = floor($toconver / 60 % 60);
         $secs = floor($toconver % 60);
         $timeFormat = sprintf('%02d:%02d:%02d', $hours, $mins, $secs);
         echo $timeFormat;
      ?></td>
</tr>

<?php
}
?>

【问题讨论】:

  • 您要为多少用户拉取数据?
  • 最多 300 名玩家
  • 我更新了答案

标签: php json performance loops


【解决方案1】:

防止多次调用 API 的唯一方法是找到同义数据点。幸运的是,Steam 提供了这一点。

根据Steam API on GetPlayerSummaries,您最多可以同时返回100名玩家的数据。因此,您应该只需要一次进行此调用(假设您只获取有关少数玩家的数据)。

在您的foreach ($return as $user) 中,您当前正在将$user 传递给查询本身:

&amp;steamids=$user-&gt;SteamID

这充当GET参数,并调用多个url:

/GetPlayerSummaries/v0002/?key=$devkey&steamids=12345678
/GetPlayerSummaries/v0002/?key=$devkey&steamids=23456789

这显然非常昂贵,但幸运的是,您可以使用 Comma-delimited list of 64 bit Steam IDs to return profile information for 一次传递所有 ID。因此,您应该将此列表创建为一个变量以一次性发送所有内容:

$combined_ids = '';
foreach ($return as $user) {
  $combined_ids.= $user->SteamID . ',';
}
// $combined_ids = '1,2,3,4,5';

然后,您可以将此变量传递到查询中,在循环之外

$link = "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=$devkey&steamids=$combined_ids";
$json = file_get_contents($link);
$decoding = json_decode($json);

最后,单次调用 API 之后,您将使用预定义的 $decoding 对每个用户的结果进行 secondary 循环变量。

<?php foreach ($return as $user) {

    $avatar = $decoding->response->players[0]->avatar;
    ?>
    <td id="addme"><img src="<?php echo $avatar; ?>" width="32" height="32"></td>
    <td><?php echo $user->DisplayName; ?></td>
    <td><?php echo $user->SteamID; ?>  <a href="http://steamcommunity.com/profiles/<?php echo $user->SteamID; ?>/" target="_blank"><span class="glyphicon glyphicon-new-window" id="gotosteamprofile"></span></a></td>
    <td><?php
    $ipredc = substr($user->Address, 0, -6);
    echo $ipredc; ?></td>
    <td><?php 
    $toconver = $user->ConnectedSeconds;
    $hours = floor($toconver / 3600);
    $mins = floor($toconver / 60 % 60);
    $secs = floor($toconver % 60);
    $timeFormat = sprintf('%02d:%02d:%02d', $hours, $mins, $secs);
    echo $timeFormat;
    ?></td>
    </tr>

<?php
}
?>

请注意,您可能需要根据一次处理多个用户而不是一次处理一个用户的 API 的返回来稍微调整结果。

希望这会有所帮助! :)

【讨论】:

  • 我真的很喜欢这个主意。我早该想到的!我必须检索多达 300 名玩家,所以我想将其分成 3 x 100 并进行 3 次查询是要走的路!
  • 正确 :) 只需使用三组不同的 $combined_ids 将循环分成三个不同的段 :)
  • 工作得很好,而且肯定会减少加载时间!只有一件事,它会在每一行显示相同的头像。我尝试每次都增加值以检索每个 steamid 的正确头像,但我无法使其工作
  • 这将(可能)来自players[0] in $avatar。您可能需要使用$user 代替那里的零:)
  • $avatar = $decoding->response->players[$user]->avatar;做到了,HTML 中的输出是空的
【解决方案2】:

根据文档,您可以传递逗号分隔的最多 100 个 id 的字符串。

返回个人资料信息的 64 位 Steam ID 的逗号分隔列表。最多可申请 100 个 Steam ID enter link description here

所以根据我对评论的回答,你可以这样做:

$allRows = []; // initialize all rows array

// organize the database result into an array as such
$allSteamUsers = [
    '76561197989628222'=>['Address'=>'Some Address 1','DisplayName'=>'Some Name'], // => some data
    '76561197989628233'=>['Address'=>'Some Address 2','DisplayName'=>'Some Name'], // => some data
    '76561197989628444'=>['Address'=>'Some Address 3','DisplayName'=>'Some Name'], // => some data
    // .......
    '76561197989628447'=>['Address'=>'Some Address 298','DisplayName'=>'Some Name'], // => some data
    '76561197989628448'=>['Address'=>'Some Address 299','DisplayName'=>'Some Name'], // => some data
    '76561197989628449'=>['Address'=>'Some Address 300','DisplayName'=>'Some Name'], // => some data
];

// chunk the user array into parts of 100 and preserve keys
$steamUsersChunks = array_chunk($allSteamUsers, 100, true);

// loop parts
foreach($steamUsersChunks as $steamUsers){

    // build the comma separated id string for the query
    $steam_ids_str = implode(',',array_keys($steamUsers));

    $url = "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=$devkey&steamids=$steam_ids_str";
    $items = json_decode(file_get_contents($url),true); // get JSON and decode with associative array flag set to true
    $players = $items['response']['players']; // get the players array

    $rows = [];

    // loop players array
    foreach($players as $item) {

        // set your variables
        $steamId = $item['steamid'];
        $avatar = $item['avatar'];
        $user_displayName = $steamUsers[$steamId]['DisplayName'];
        $user_Address = $steamUsers[$steamId]['Address'];
        $ipredc = substr($user_Address, 0, -6);

        // build row and add to rows container of this players loop
        $rows[] = '<tr>
        <td id="addme"><img src="'.$avatar.'" width="32" height="32"></td>
        <td>'.$user_displayName.'</td>
        <td>'.$steamId.'  <a href="http://steamcommunity.com/profiles/'.$steamId.'/" target="_blank"><span class="glyphicon glyphicon-new-window" id="gotosteamprofile"></span></a></td>
        <td>'.$ipredc.'</td>
        <td></td>
        </tr>';

    }

    // attach to the general table
    $allRows[] = implode("\n",$rows);

}

// display rows where ever needed
echo implode("\n",$allRows);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多