я использую https://github.com/bandwidth-throttle/token-bucket для запросов, ограниченных внешним сервером.
Мой код:
function main() {
unlink(__DIR__ . "/api.bucket2");
$storage = new FileStorage(__DIR__ . "/api.bucket2");
$rate = new Rate(3, Rate::SECOND);
$bucket = new TokenBucket(3, $rate, $storage);
$bucket->bootstrap(3);
$consumer = new BlockingConsumer($bucket);
for ($i = 0; $i < 12; $i++) {
$consumer->consume(1);
work();
}
}
function work() {
echo date("d.m.Y H:i:s") . substr((string)microtime(), 1, 4) . "\n";
}
main();
Результат:
-bash-4.2$ php -f worker-test.php
03.05.2016 14:26:16.785
03.05.2016 14:26:16.785
03.05.2016 14:26:16.786
03.05.2016 14:26:17.118
03.05.2016 14:26:17.451
03.05.2016 14:26:17.784
...
Я ожидал, что функция будет вызываться 3 раза в секунду, но это не так. Первые 6 звонков были в 1 секунду. если я изменю «$ bucket-> bootstrap (3);» на «$ bucket-> bootstrap (0);», будет лучше:
03.05.2016 14:33:34.913
03.05.2016 14:33:35.245
03.05.2016 14:33:35.578
03.05.2016 14:33:35.911
...
но это все еще больше, чем 3 в секунду. Что я делаю неправильно?
$bucket->bootstrap(3);
TokenBucket::bootstrap(3)
кладет три начальных жетона в ведро. Эти начальные токены можно использовать мгновенно. Вы фактически не ограничиваете скорость для тех первых вызовов.
Если вы не хотите этот начальный пакет, вы правильно загрузили его без каких-либо токенов.
03.05.2016 14:33:34.913 03.05.2016 14:33:35.245 03.05.2016 14:33:35.578 03.05.2016 14:33:35.911
но это все еще больше, чем 3 в секунду.
Я считаю 3 в секунду. Пожалуйста, допустите это наблюдаемое отклонение ± 1 мс. В долгосрочной перспективе вы получите в среднем 3 в секунду.
Это ± 1мс приходит, вероятно, из эта реализация подробно из BlockingConsumer
:
// sleep at least 1 millisecond.
usleep(max(1000, $seconds * 1000000));
Других решений пока нет …