2

マッシュアップ用に last.fm の API を介して大量のユーザー データを取得しています。リスニングデータを収集する必要があるため、これを毎週行います。

REST API と XML を介してデータを取得します。具体的にはsimplexml_load_file().

スクリプトはとてつもなく長くかかります。約 2,300 人のユーザーの場合、スクリプトはアーティストの名前だけを取得するのに 30 分かかります。今すぐ修正する必要があります。そうしないと、ホスティング会社が閉鎖されてしまいます。他のすべてのオプションを吸い上げました。スクリプトの速度を低下させているのは XML です。

ここで、last.fm の API が遅い (または、通知なしに呼び出しが制限されている) かどうか、または PHP の simplexml が実際にかなり遅いかどうかを把握する必要があります。

私が気づいたことの 1 つは、XML 要求が必要以上に取得することですが、API を介してそれを制限することはできません (つまり、70 ではなく 3 バンドのみに関する情報を提供してください)。しかし、「大きな」XML ファイルは約 20kb しかありません。スクリプトの速度が低下している可能性がありますか? 2300 人のユーザーごとに 20kb をオブジェクトにロードする必要がありますか?

それができるという意味がありません...おそらくlast.fmの遅いAPIであることを確認する必要があります。またはそれは?

あなたが提供できる他の助けはありますか?

4

5 に答える 5

1

単純な xml はそれほど遅いとは思いません。パーサーなので遅いのですが、2300 の curl/file_get_contents にはもっと時間がかかっていると思います。また、データをフェッチせずに simplexml_load_string を使用するのはなぜですか。それらのファイルをサーバーのディスクに配置する必要がありますか?

少なくともメモリからロードすると、少し速度が向上するはずです。また、ロードされた xml に対してどのような処理を行っていますか? 処理が可能な限り効率的であると確信していますか?

于 2009-09-26T12:37:21.907 に答える
1

last.fm からダウンロードした XML が gzip されていることを確認してください。サーバーに gzip をサポートしていることを伝えるには、おそらく正しい HTTP ヘッダーを含める必要があります。ダウンロードは高速化されますが、解凍部分でより多くのサーバー リソースが消費されます。

また、非同期ダウンロードを使用してサーバー リソースを解放することも検討してください。必ずしもプロセスが高速化されるわけではありませんが、サーバー管理者は満足するはずです。

XML 自体が大きい場合は、DOM パーサーの代わりに SAX パーサーを使用します。

于 2009-09-26T14:59:43.873 に答える
1

20kb * 2300 ユーザーは最大 45MB です。~25kB/秒でダウンロードしている場合、データをダウンロードするだけで 30 分かかります。

于 2009-09-26T12:57:04.490 に答える
0

1 秒あたり 1 回の API 呼び出しに制限があると思います。このポリシーがコードによって強制されているかどうかはわかりませんが、何か関係があるかもしれません。これが事実であると思われる場合は、 irc.last.fm #audioscrobblerで IRC の Last.fm スタッフに尋ねることができます。

于 2009-09-26T15:10:15.203 に答える
0

提案されているように、データをフェッチして、にsimplexml_load_string依存するのではなく、を使用して解析しsimplexml_load_fileます。約 2 倍の速さで動作します。ここにいくつかのコードがあります:

function simplexml_load_file2($url, $timeout = 30) {


// parse domain etc from url
$url_parts = parse_url($url);
if(!$url_parts || !array_key_exists('host', $url_parts)) return false;

$fp = fsockopen($url_parts['host'], 80, $errno, $errstr, $timeout);
if($fp) 
{
    $path = array_key_exists('path', $url_parts) ? $url_parts['path'] : '/'; 
    if(array_key_exists('query', $url_parts)) 
    {
        $path .= '?' . $url_parts['query'];
    }

    // make request
    $out = "GET $path HTTP/1.1\r\n";
    $out .= "Host: " . $url_parts['host'] . "\r\n";
    $out .= "Connection: Close\r\n\r\n";

    fwrite($fp, $out);

    // get response
    $resp = "";
    while (!feof($fp))
    {
        $resp .= fgets($fp, 128);
    }
    fclose($fp);

    $parts = explode("\r\n\r\n", $resp);
    $headers = array_shift($parts);

    $status_regex = "/HTTP\/1\.\d\s(\d+)/";
    if(preg_match($status_regex, $headers, $matches) && $matches[1] == 200)
    {
        $xml = join("\r\n\r\n", $parts);    
        return @simplexml_load_string($xml);            
    }   

}
return false; }
于 2012-04-03T08:38:57.140 に答える