20
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

いい感じにsleepする

Last updated at Posted at 2013-01-27

バッチ処理などで、リソース(APIやDBなど)にアクセスする際に次のようなコードを書いたことある人は多いのではないでしょうか。

crawler_without_throttle_proc.php
<?php
$page = 1;
while ( $result = $api->fetch("/some/api?page=" + $page) ) {
   $cache->set($result);
   if ( $page % 10 === 0 ) {
      sleep(1);
   }
}

このコードには、(問題にならないことも多いでしょうが)いくつか問題があります。

10回に1回のsleepで大丈夫とは限りません。もしかすると、9回目のアクセスでAPIを提供するサイトが負荷がかかって重くなってしまうかもしれません。
1秒のスリープをしたとしても、ちょうど1秒後のアクセスのタイミングで、他のユーザーの大量のアクセスが集中すれば、結果的にAPIを提供するサイトは重くなってしまいます。

というわけで、ThrottleProcというライブラリを作ってみました。(Composerでもそのうち提供する予定です。)

これを使って書くと次のような感じになります。

crawler_with_throttle_proc.php
<?php
require_once('path/to/lib/src/ThrottleProc.php');

$throttle = new ThrottleProc(0.1);
$page = 1;
while ( true ) {
  $throttle->start();
  $result = $api->fetch("/some/api?page=" + $page);
   if ( $result === null ) {
      break;
   } else {
        $cache->set($result);
        $throttle->finishAndSleep();
   }
}

もちろんこれで重くならない、というわけではないのですが、cacheにセットする処理に時間がかかったり、apiを取得する処理に時間がかかった場合、それに応じて間隔を自動調整してくれるので、重いリクエストを投げ続けてさらに負荷をかける、というのを緩和できます。

ruby版も前に作りましたが、perlのSub::Throttleを移植したライブラリです。phpだとClosureを受けるという方式だとちょっと都合が悪いことがありそうだったので、呼び出しがstart/finishAndSleepと分かれています。

20
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?