0

私は基本的に、さまざまなAPIからデータを取得し、PHPを使用してそれらをまとめています-Webマッシュアップのように。現在、4つのforeeachステートメントを使用して、収集したデータを個々の配列に挿入しています。PHPデータを表示しているページをロードするのにおそらく3秒ほどかかるので、現在のコードは非効率的だと思います。以前は、すべてのデータを一度に調べて印刷するための大きなforeachループが1つしかありませんでした。しかし、それも私には非効率だと感じました。

では、コードの処理を高速化するという点で、コードをより効率的にするにはどうすればよいでしょうか。Soundeerなど、1秒程度で読み込まれるマッシュアップWebサイトをいくつか見ました。それは彼らのコード効率のせいですか?

私が使用しているコードは次のとおりです。

$echonest_uri = simplexml_load_file("http://developer.echonest.com/api/v4/artist/search?api_key=$APIkey&style=rap&results=10&start=$element_num&bucket=id:deezer&bucket=images&sort=familiarity-desc&format=xml");

//Swap the comments for when in UWE or not
//$echonest_xml =  new SimpleXMLElement($echonest_uri);
$echonest_xml = $echonest_uri;

$artist_name = array();
$artist_image = array();
$echonest_id = array();
$full_deezer_id = array();
$deezer_id = array();
$num_of_albums = array();

//Loop through each entries in the id_arr and make each image of the artist a link to the album page passing all the relevant information. 
foreach($echonest_xml->artists->artist as $artist){
    $artist_name[] = $artist->name;
    $artist_image[] = $artist->images->image[0]->url;
    $echonest_id[] = $artist->id;
    $full_deezer_id[] = $artist->foreign_ids->foreign_id->foreign_id;
}

foreach($full_deezer_id as $key => $value){
    preg_match('#deezer:artist:([A-Z,a-z,0-9]+)#', $value, $id);
    $deezer_id[] = (string)$id[1];
}

foreach($deezer_id as $id_index => $id){
    $deezer_xml = simplexml_load_file("http://api.deezer.com/2.0/artist/$id/albums&output=xml");
    $num_of_albums[] = $deezer_xml->total;
}

//The variable which will contain the HTML code to display the artists.
$output = null;


foreach($deezer_id as $key => $value){

    $fav_count_query = "SELECT COUNT(user_index) FROM fav_artist WHERE artist_deezer_id = '$value'";
    $fav_count_resource = $mysqli->query($fav_count_query);
    $fav_count = $fav_count_resource->fetch_assoc(); 

    $output .=  <<<HERE
                <div class="artist-container">
                    <a href="albums.php?echonest_id={$echonest_id[$key]}&deezer_id={$deezer_id[$key]}&artist_name={$artist_name[$key]}&artist_image={$artist_image[$key]}&num_of_albums={$num_of_albums[$key]}" class="artist-image">
                        <img src="{$artist_image[$key]}" alt="{$artist_name[$key]}" title="{$artist_name[$key]}"/>
                    </a>

                    <a href="albums.php?echonest_id={$echonest_id[$key]}&deezer_id={$deezer_id[$key]}&artist_name={$artist_name[$key]}&artist_image={$artist_image[$key]}&num_of_albums={$num_of_albums[$key]}" class="artist-name">
                        {$artist_name[$key]}
                    </a>
                    <a href="albums.php?echonest_id={$echonest_id[$key]}&deezer_id={$deezer_id[$key]}&artist_name={$artist_name[$key]}&artist_image={$artist_image[$key]}" class="album-number">Albums: 
                        {$num_of_albums[$key]}
                    </a>
                </div>
HERE;

}
4

2 に答える 2

3

foreachループが複数あるため、コードが遅くなることはほとんどありません(正直なところ、現実的なシナリオでは違いを感じることはありません)。ここであなたを傷つけているのは、外部サイトから何かをダウンロードしていることです。

私の解決策は、これを5分ごとに(cronジョブを介して、またはユーザーがページにアクセスしたときに)自動的にダウンロードし、5分未満の場合は、サーバーに配置されたキャッシュバージョンを表示することです。

はいえ、これは検索のようですので、結果はほとんど変わらないでしょう。多分代わりに1日のキャッシュがありますか?(新しい検索クエリごとに3秒かかりますが、多くのユーザーが同じクエリを実行することが予想される場合は、サイトがはるかに高速に見えるようになります)。

コード内で時間的に問題が発生している場所をテストする簡単な方法は、microtime関数を使用することです。私が通常行うことは次のようなものです:

$beforeCall = microtime(true);
$echonest_uri = simplexml_load_file("http://developer.echonest.com/api/v4/artist/search?api_key=$APIkey&style=rap&results=10&start=$element_num&bucket=id:deezer&bucket=images&sort=familiarity-desc&format=xml");
echo "The call took " . number_format(microtime(true) - $beforeCall, 4) . " seconds";

XMLを使用している場合(これはそう思われます)、キャッシュを有効にしてSimplePieを使用できます。このための良い記事は、キャッシュシステムに関するSimplePie自身の記事であり、でキャッシュ期間を調整できますset_cache_duration

于 2013-01-19T20:20:11.987 に答える
2

キャッシング

最も関連性が高いのは、キャッシュです。api呼び出しの結果をキャッシュする単純な実装は次のようになります。

$url = "http://developer.echonest.com/api/v4/artist/search?api_key=$APIkey&style=rap&results=10&start=$element_num&bucket=id:deezer&bucket=images&sort=familiarity-desc&format=xml";
$cacheFile = md5($url) . '.xml';

// If the cache file exists and is less than an hour old - use it.
if (file_exists($cacheFile) && filemtime($cacheFile) > (time() - 3600)) {
    $xml = file_get_contents($cacheFile);
// else download it
} else {
    $xml = file_get_contents($url);
    file_put_contents($cacheFile, $xml);
}
$xml = simplexml_load_file($cacheFile);

つまり、リクエストごとにAPIを話さないでください。一度話して、有効であると見なすことが適切/安全であると判断する限り(上記の例では、3600秒または1時間)応答を使用してください。

この種のロジックは、メソッドにカプセル化するのが最適です。

DRYコードの実行

キャッシングと比較して重要性は低いですが、問題のコードは、相互にフィードする4つのforeachループです。これは、このようなロジックを作成するための効率的な方法ではありません。実行されたコードに自分自身を繰り返さないでください。つまり、次のように適用することをお勧めします。

foreach($echonest_xml->artists->artist as $artist){
    ...
    $full_deezer_id[] = $artist->foreign_ids->foreign_id->foreign_id;
}

foreach($full_deezer_id as $key => $value){ // <--
    ...
    $deezer_id[] = (string)$id[1];
}

foreach($deezer_id as $id_index => $id){ // <--
    ...
}

foreach($deezer_id as $key => $value){ // <--

次のように書く方がよい

foreach($echonest_xml->artists->artist as $artist){
    processArtist($artist);
}

foreach($buidThis as $row) {

したがって、同じデータに対して4回ではなく、最大2回(ただし、できれば1回だけ)ループするコードを記述します。

問題のロジックのみを使用すると、これは次のようになります。たとえば、最初の2つのループを簡単に組み合わせることができます。

foreach($echonest_xml->artists->artist as $artist){
    preg_match('#deezer:artist:([A-Z,a-z,0-9]+)#', $artist->foreign_ids->foreign_id->foreign_id, $id);
    $deezer_id[] = (string)$id[1];
}

同じ分析をすべてのコードに適用する必要があります。反復/再帰ロジックの量を制限するようにしてください。

于 2013-01-19T20:27:29.087 に答える