Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance of asyncio

I'm trying to get familiar with asyncio, so I've decided to write a database client. However, performance exactly matches synchronous code. I'm sure this is my misunderstanding of a concept. Could someone explain what am I doing wriong?

Please see example of code below:

class Connection:
    def __init__(self, reader, writer, loop):
        self.futures = deque()

        # ...

        self.reader_task = asyncio.async(self.recv_data(), loop=self.loop)

    @asyncio.coroutine
    def recv_data(self):
        while 1:
            try:
                response = yield from self.reader.readexactly(4)
                size, = struct.unpack('I', response)
                response = yield from self.reader.readexactly(size)

                # ...                

                future = self.futures.popleft()

                if not future.cancelled():
                    future.set_result(response)

            except Exception:
                break

    def send_data(self, data):
        future = asyncio.Future(loop=self.loop)
        self.futures.append(future)

        self.writer.write(data)

        return future


loop = asyncio.get_event_loop()


@asyncio.coroutine
def benchmark():
    connection = yield from create_connection(loop=loop, ...)

    for i in range(10000):
        yield from connection.send_data(...)


s = time.monotonic()

loop.run_until_complete(benchmark())

e = time.monotonic()
print('Requests per second:', int(10000 / (e - s)))

Thanks in advance.

like image 995
Andrew Avatar asked Feb 06 '15 16:02

Andrew


People also ask

Is Asyncio faster?

Standard library asyncio is definitely slower than most multi-threaded frameworks, because asyncio executes a lot of Python for each event. Generally frameworks are faster the more that they're implemented in C or another compiled language.

Is Asyncio faster than threading?

One of the cool advantages of asyncio is that it scales far better than threading . Each task takes far fewer resources and less time to create than a thread, so creating and running more of them works well.

Is Asyncio slow?

Actually, asyncio is much slower due to the high impact of using coroutines. I have no numbers, so this is just a comment, instead of a post, but you can verify this with a simple http echo server written in both styles. Python + high performance async IO do not work together, sadly.

Why is Asyncio better than threads?

Asyncio vs threading: Async runs one block of code at a time while threading just one line of code at a time. With async, we have better control of when the execution is given to other block of code but we have to release the execution ourselves.


2 Answers

You've made a mistake in the way you're calling send_data. Right now, you've got this:

@asyncio.coroutine
def benchmark():
    connection = yield from create_connection(loop=loop, ...)

    for i in range(10000):
        yield from connection.send_data(...)

By using yield from inside the for loop, you're waiting for the future you're returning from send_data to yield a result before moving on to the next call. This makes your program basically synchronous. You want to make all your calls to send_data, and then wait for results:

@asyncio.coroutine
def benchmark():
    connection = yield from create_connection(loop=loop, ...)
    yield from asyncio.wait([connection.send_data(..) for _ in range(10000)])
like image 109
dano Avatar answered Nov 09 '22 06:11

dano


The python asyncio module is single threaded:

This module provides infrastructure for writing single-threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network clients and servers, and other related primitives.

This question has an explanation of why asyncio can be slower than threading, but in short: asyncio uses a single thread to execute your code, so even if you have multiple coroutines, they all execute serially. A thread pool is used to execute some callbacks and I/O. Because of the GIL, threading also executes user code serially, though I/O operations can be run synchronously.

The reason using asyncio doesn't give you an improvement over serially executed code, is because the event loop is only running one coroutine at a time.

like image 41
zstewart Avatar answered Nov 09 '22 05:11

zstewart