使用asyncio进行速率限制协程

时间:2017-10-21 19:39:56

标签: python python-3.x async-await python-asyncio

我需要能够对来自协程的调用进行速率限制(我需要在每次用户更改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()

0 个答案:

没有答案