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

@request_limiter = TimedRateLimiter.new 3, 3, 1;
and call
@request_limiter.consume;

In reply to Re: do something no more than 3 times a second by ambrus
in thread do something no more than 3 times a second by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.