8

私はシンプルなチャットアプリに取り組んでおり、おそらく 1 部屋あたり 10 人から 20 人のユーザーです。

データベースに新しいメッセージを問い合わせるスクリプトは、取得するすべてのリクエストに対して単純すぎるように見えます。

以下は、新しいメッセージをループするコードのブロックです。スクリプトの残りの部分は、変数、クエリの構築、および json 応答オブジェクトを取得するだけです。

$sleepTime = 1; //Seconds
$data = "";
$timeout = 0;

//Query database for data
while(!$data and $timeout < 10){
    $data = getQuery($sql);
    if(!$data){
        //No new messages on the chat
        flush();
        //Wait for new Messages
        sleep($sleepTime);          
        $timeout += 1;
    }else{
        break;
    }
}

上記のブロックは、データベースに新しいメッセージを 10 秒ごとにクエリし、10 秒後に新しいメッセージがない場合はブラウザに通知します。ブラウザは 5 秒間待ってから、別のリクエストを送信して新しいメッセージを取得します。

ただし、スクリプトが新しいメッセージを見つけた場合、ブラウザは、サーバーから新しいメッセージの応答を受け取るとすぐに、さらに新しいメッセージを要求します。

このプロセスは延々と続きます...

では、このプロセスをさらに最適化するにはどうすればよいでしょうか? これでいいのか?私のローカルサーバーでは正常に動作していますが、少数のユーザーがすべてのリクエストとループでライブサーバー (共有ホスト) を過負荷にする可能性があるのではないかと心配しています。

これは、firebug http://pixbush.com/chat/chat.phpで確認できるライブデモです。

4

4 に答える 4

3

あなたの説明から、あなたは5秒間の沈黙のギャップを持っているように聞こえますが、これはロングポーリングの利点を打ち負かします。呼び出しがサーバーから(長いまたは短い)戻ってきたら、ブラウザーにすぐに別の要求を開始させます。バックアップとして、サーバーを呼び出すたびに、ブラウザーにサーバー側のタイムアウトよりもわずかに長いタイムアウトを開始させますが、要求が返されたときにキャンセルします。サーバーリクエストが失敗し、ブラウザのタイムアウトが完了した場合は、新しいリクエストを開始します。

于 2010-10-26T21:19:35.067 に答える
2

これは AJAX に悲鳴を上げます。

JavaScript 応答を PHP に送信する方法については、今日の私の投稿を参照してください。スクリプトがループしなければならない理由はまったくありません。


編集: AJAX についての私の悪い。IRC チャットボットPHP-Eggを作成したとき、この問題 * 100 に遭遇しました。私がそれを解決した方法 (PHP の 4 日前にさかのぼります) は、 PHP のpcntl_fork()を使用して、メッセージ。利点は、sleep() とは異なり、CPU を 100% ブロックせず、10 秒または任意の制限よりもはるかに高速であることです。


私は再び答えを修正しています(申し訳ありません!):

テキストをファイルにダンプするある種の非同期プロセスを使用します。

次に、あなたがすることは

if (filemtime('chat.log') > time() - 5) { echo json_encode(file_get_contents('chat.log')); }

利点: SQL の使用が制限されます。ループする必要はありません。

于 2010-09-02T01:53:34.837 に答える
1

私はウェブチャットをしていて、リアルタイムの更新を維持するための同じソリューションに出くわしました。だから、あなたがそれを理解したかどうか疑問に思います:sleep()関数を使用してサーバー側をループし続けるのは良い方法ですか、それとも代わりにもっと多くのajaxクエリを使用する方が良いでしょう。そして、sleep()関数は本当に良い考えであり、いくつかのユーザーがポーリングしているときにサーバーを停止しませんか?

SOチャットアプリでmeeboがロングポーリング(クエリ間の時間もウィンドウフォーカスに依存すると思います)を使用しているのがわかります。ただajaxクエリを使用しているようです。だから私は不思議に思う。

于 2010-11-23T20:01:39.110 に答える
0

DB の代わりに conversationId に従ってラベル付けされたファイルを使用してみて、ファイルが「タッチ」されているかどうかを確認してください。また、usleep と set_time_limit (Windows サーバーの場合) を使用して間隔をミリ秒単位で設定し、スリープ時間を増やします。実際には、Usleep は CPU 使用率を遅らせますが、ファイルが変更された場合でも即座に起動します。

これが私のチャット スクリプトのセクションです。=)

define('SUCCESS', '__SUCCESS__');
define('FAILED', '__FAILED__');

$tmpLib = $TMPFOLDER;
$msgPath = $MSGFILE;

$timeout = $POLLSPEEDSEC;

$acct = new Account($tmpLib, $_GET['key']);

if (false === $acct) {
    return false;
}

$msg = new Message($msgPath, $acct);

$lastMod = !empty($_GET['ts']) ? $_GET['ts']: 0;
$lastMod = substr($lastMod, 0, 10);
$lastMod = (int)$lastMod;

$result = array();

$start = gettimeofday();
$prevMsg = $acct->getTemp('cache');

do{
    usleep(10000);

    if ($acct->getFileTime() >= $lastMod) {
        $result['account'] = $acct->getAllOnline();
    }

    if($msg->getFileTime() >= $lastMod) {
        $result['message'] = $msg->fetch();
    }

    if (!empty($result)) {
        $theMsg = json_encode($result);
        if ($theMsg != $prevMsg) {
            $acct->setTemp('cache', $theMsg);
            echo $theMsg;
            flush();
            exit;
        }
        $result = array();
        $lastMod = time();
    }

    $end = gettimeofday();
} while($timeout > ($end['sec'] - $start['sec']));

echo FAILED;
于 2010-09-02T02:38:43.320 に答える