in reply to do something no more than 3 times a second
I have some such code in the source of cbstream, but there it's completely unnecessary so I can donate it to you. (Technical details: I'm using it to limit the amount of text sent to the irc server so it doesn't kick the client, but that limit is not a constant, and instead I should be sending a PING command in every 1024 bytes and wait till the PONG that shows the server has processed the data).
Search for TimedRateLimiter in the cbstream source code. The way the implementation works is that it stores two numbers: a count that tells how many more requests you could send (this could be fractional), and the timestamp of when you last updated that first number. When you try to send a request, you first update the first number by increasing it by 3 s-1 times the time that has passed since the timestamp and updating the timestamp, then clamp the first number from above. Then, you check if the first number is at least 1: if it is, you can send a request now, you only need to decrease the number by 1; if it's less than 1, you have to sleep for the approperiate amount.
Here's a snapshot of the relevant parts of the source code for prosperity.
class TimedRateLimiter; # not completely reliable if called from multiple threads # rate is unit per second def initialize rate, max, credit; @rate, @max = rate, max; 0 < rate or fail "invalid rate for TimedRateLimiter"; 0 < max or fail "invalid max for TimedRateLimiter"; @time = Time.now; @tally = if credit < 0; 0 else credit end; @lock = Mutex.new; end; def update; time = Time.now; @tally += (time - @time) * @rate; if @max < @tally; @tally = @max; end; @time = time; end; def consume amt = 1; slp = (); @lock.synchronize do 0 <= amt or amt = 0; update; if @tally < amt; slp = Float(amt - @tally) / @rate; end; end; if slp sleep slp; end; @lock.synchronize do @tally -= amt; end; true; end; def try_consume amt = 1; r = false; @lock.synchronize do 0 <= amt or amt = 0; update; if amt <= @tally; @tally -= amt; r = true; end; end; r; end; end;
In your case, you'd need to construct a limiter, say
and call@request_limiter = TimedRateLimiter.new 3, 3, 1;
@request_limiter.consume;
|
|---|