我需要能够对来自协程的调用进行速率限制(我需要在每次用户更改UI滑块中的值时发出网络请求,但为了避免产生大量网络请求,我希望将它们限制为大多数每100毫秒一次)。同样重要的是,最后一次通话将永远执行,永不掉线。
这是我到目前为止所做的,但似乎有点笨重。有更好的方法吗?
import asyncio
class RateLimit:
def __init__(self, rate, loop):
self.rate = rate
self.loop = loop
self.last_time = loop.time()
self.last_coro = None
self.waiting = False
@property
def ready(self):
return self.loop.time() - self.last_time >= self.rate
async def _run(self):
while not self.ready:
await asyncio.sleep(self.rate)
self.last_time = self.loop.time()
coro = self.last_coro
self.last_coro = None
self.waiting = False
if coro:
asyncio.ensure_future(coro, loop=self.loop)
def run(self, coro):
if self.last_coro:
self.last_coro.close()
self.last_coro = coro
if not self.waiting:
self.waiting = True
asyncio.ensure_future(self._run(), loop=self.loop)
async def printer(val, loop, *, timeout=0.5):
# await asyncio.sleep(timeout)
print(val, loop.time())
async def main(loop):
limiter = RateLimit(1, loop=loop)
print('starting rate limit loop test')
t = loop.time()
# Hit the rate limiter with a bunch of calls in a row.
# Should only print something once a second.
for i in range(1000000):
limiter.run(printer(i, loop))
# Hand control back to the event loop
await asyncio.sleep(0)
print('done in {}s'.format(loop.time() - t))
if __name__ == '__main__':
loop = asyncio.get_event_loop()
asyncio.ensure_future(main(loop), loop=loop)
loop.run_forever()