ホームページ >バックエンド開発 >PHPチュートリアル >PHP uniqid 関数の実行速度の遅さに関連する問題

PHP uniqid 関数の実行速度の遅さに関連する問題

WBOY
WBOYオリジナル
2016-06-13 12:05:381197ブラウズ

PHP の uniqid 関数
の実行が遅いという問題 少し前の要件: すべての端末 (PC、パッド、電話) に適したスクラッチ カード アクティビティ用の H5 ページを作成するための簡単なフォームを顧客が送信し、それを生成する必要があります。オンライン機能では賞品コードの数に6Wの制限があります。

各イベントの賞品コードを一意に保つ必要があるため、最初に PHP の uniqid 関数を使用して UUID (Universally Unique IDentifier、GUID とも呼ばれ、アルゴリズムによって生成されるグローバルに一意な識別子) を生成する準備をします。 )を生成します。

しかし、テストのために 1W を生成していたとき、データベースに挿入する時間を除いて、生成に数十秒かかることがわかりました。そこで、パフォーマンス テスト用に xhprof を使用した簡単な例を作成しました。

<?phpxhprof_enable(XHPROF_FLAGS_CPU|XHPROF_FLAGS_MEMORY);function   myfunc(){    for($i=0;$i<10000;$i++){        $data = uniqid();    }}myfunc();$data = xhprof_disable();print_r($data);

テスト結果:

[myfunc==>uniqid] => Array(            [ct] => 10000            [wt] => 39975062            [cpu] => 0            [mu] => 960752            [pmu] => 0)

は、実際には 1 回の実行に 3969 マイクロ秒かかり、生成には 0.003969 秒かかります。ユーザーがフォームの送信と引き換えコードの生成を同時に行うと、最悪の場合、ユーザーへの応答に 4 分かかります。 もちろん、メッセージ キューを使用して非同期に生成することもできますが、uniqid はなぜそれほど時間がかかるのでしょうか。単純な文字列を生成するのに時間がかかるでしょうか?

次に、uniqid の実装ソースコードを確認します。
PHP_FUNCTION(uniqid){     char *prefix = "";#if defined(__CYGWIN__)     zend_bool more_entropy = 1;#else     zend_bool more_entropy = 0;#endif     char *uniqid;     int sec, usec, prefix_len = 0;     struct timeval tv;     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sb", &prefix, &prefix_len,                                     &more_entropy)) {          return;     }#if HAVE_USLEEP && !defined(PHP_WIN32)     if (!more_entropy) {#if defined(__CYGWIN__)          php_error_docref(NULL TSRMLS_CC, E_WARNING, "You must use 'more entropy' under CYGWIN");          RETURN_FALSE;#else          usleep(1);#endif     }#endif     gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);     sec = (int) tv.tv_sec;     usec = (int) (tv.tv_usec % 0x100000);     /* The max value usec can have is 0xF423F, so we use only five hex     * digits for usecs.     */     if (more_entropy) {          spprintf(&uniqid, 0, "%s%08x%05x%.8F", prefix, sec, usec, php_combined_lcg(TSRMLS_C) * 10);     } else {          spprintf(&uniqid, 0, "%s%08x%05x", prefix, sec, usec);     }     RETURN_STRING(uniqid, 0);}


ロジックを見ると、これも複雑な処理はありません。現在の時刻の秒とマイクロ秒を入力し、1W 回実行するのに 2000 マイクロ秒かかる単純なテストを作成しました。これはなぜでしょうか。ただし、生成された uid に多くの重複があることがわかりました。このため、元のコードの usleep 関数に注目し、さらに usleep 関数をテストしました。 PHP の結果は、毎回異なる uid を生成するためにここにあります。
usleep 関数で問題が発生し、usleep の前後に間隔時間を追加すると、次のコードになります。
int getUniqid( char * uid) {     int sec, usec;     struct timeval tv;     gettimeofday(( struct timeval *) &tv, ( struct timezone *) NULL);     sec = ( int) tv. tv_sec;     usec = ( int ) (tv.tv_usec % 0x100000);     sprintf(uid, "%08x%05x" , sec, usec);     return 1;}



最終的に、時間がかかることが判明しました。 1W 賞品コードを生成するのに 39.99587739.995877 秒かかり、合計の usleep 間隔時間は 39.982442m です。 usleep 時間を出力すると、usleep(1) がプロセスの一時停止から復帰までに毎回 4000 マイクロ秒かかることがわかります。 usleep では精度を達成できず、その差が大きすぎることを知ってください。
最後に、次のコードを使用して賞品コードを生成しました

 struct timeval start, end;      gettimeofday(( struct timeval *) &start, ( struct timezone *) NULL);      usleep(1);      gettimeofday(( struct timeval *) &end, ( struct timezone *) NULL);      unsigned long space = (end.tv_sec - start. tv_sec) * 1000000 + end.tv_usec              - start. tv_usec;       spaceCost += space;
uuid テスト コードが付属しています



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。