News for hackers. Stuff that matters.
Re:Python Asyncio: The Complete Guide by m3047 on Thursday November 10, 2022 @01:57PM (#33551346)
> 100x SLOWER (we measured it multiple times, compared the same thing to the sync version)

I'd need to know the methodology. Asyncio is "gated", meaning that coroutines execute in tranches. When you queue up a bunch of coroutines from another coroutine, they don't execute right away instead they go in a list. Then when the current tranche completes the next one starts. There's some tidying up which occurs with every tranche.

As an (only one) example of "measuring the wrong thing", if you queue up a single task 1000 times which takes as its argument a unique timer instance it matters whether you queue them up one at a time as they finish running or queue them all up at once.

    #!/usr/bin/python3
    # (c) 2022 Fred Morris, Tacoma WA USA. Apache 2.0 license.
    """Illustrating the tranche effect in asyncio."""

    from time import time
    import asyncio

    N = 1000

    class TimerInstance(object):
        def __init__(self, accumulator):
            self.accumulator = accumulator
            self.start = time()
        def stop(self):
            self.accumulator.cumulative += time() - self.start
            return
        
    class Timer(object):
        def __init__(self):
            self.cumulative = 0.0
            return
        def timer(self):
            return TimerInstance(self)

    async def a_task(timer):
        timer.stop()
        return

    def main():
        loop = asyncio.get_event_loop()
        timing = Timer()
        overall = time()
        for i in range(N):
            loop.run_until_complete( loop.create_task( a_task(timing.timer()) ) )
        print('Sequential: {}   Overall: {}'.format(timing.cumulative, time() - overall))
        timing = Timer()
        overall = time()
        for i in range(N):
            loop.create_task( a_task(timing.timer()) )
        loop.stop()
        loop.run_forever()
        print('Tranche: {}   Overall: {}'.format(timing.cumulative, time() - overall))

    if __name__ == '__main__':
        main()


    # ./tranche-demo.py 
    Sequential: 0.02229022979736328   Overall: 0.04146838188171387
    Tranche: 6.084041595458984   Overall: 0.012317180633544922

There are no comments on this comment yet.