Live data from Hacker News

Making 1M requests with Python-aiohttp

pawelmhm.github.io

11–20 of 84 posts

Re: Making 1M requests with Python-aiohttp

#11
First off, awesome to see more benchmarks (even if it's just personal experimentation) for synchronous vs asyncio performance. I think the real argument for asyncio right now is that it makes it very easy for you to write extremely efficient code, even for hobbyist projects. Even though your experiment is only handling 320 req/s, that you were able to do that so quickly and with very, very little optimization is, I think, a testament to the potential for asyncio.

Some pointers:

The event loop is still a single thread and therefore subject to the GIL. That means that at any given time, only one coroutine is running in the loop. This is important for several reasons, but probably the most relevant are that

1. within any given coroutine, execution flow will always be consistent between yield/await statements.

2. synchronous calls within coroutines will block the entire event loop.

3. most of asyncio was not written with thread safety in mind

That second one is really important. When you're doing file access, eg where you're doing "with open('frank.html', 'rb')", that's something you may want to consider moving into a run_in_executor call. That will block the coroutine, but it will return control to the event loop, allowing other connections to proceed.

Also, more likely than not, the too many open files error is a result of you opening frank.html, not of sockets. I haven't run your code with asyncio in debug mode[1] to verify that, but that would be my intuition. You would probably handle more requests if you changed that -- I would do the file access in a run_in_executor with a max executor workers of 1000. If you want to surpass that, use a process pool instead of a threadpool, and you should be ready to go, though it's worth mentioning that disk IO is hardly ever cpu-bound, so I wouldn't expect you to get much performance boost otherwise.

Also, the placement of your semaphore acquisition doesn't make any sense to me. I would create a dedicated coroutine like this:

    async def bounded_fetch(sem):
        async with sem:
            return (await fetch(url.format(i)))
and modify the parent function like this:

    for i in range(r):
        task = asyncio.ensure_future(bounded_fetch(sem))
        tasks.append(task)
That being said, it also doesn't make any sense to me to have the semaphore in the client code, since the error is in the server code.

[1] https://docs.python.org/3/library/asyncio-dev.html#debug-mod...

Re: Making 1M requests with Python-aiohttp

#12
post #7

Earlier quoted context omitted.

This is a genuine question: in what ways is Python's async implementation lacking? Could it have been baked in a better way? In what ways do languages that were supposedly designed for async programming different than Python? Python is definitely lacking an elegant interface for async programming.

I think that Python 3.5 now has a very elegant interface for async programming. I prefer Tornado to the standard library's asyncio, but the new keywords are nice for both packages (disclaimer: I'm the maintainer of Tornado). The downsides have nothing to do with the design of the language. The problem is that introducing a new concurrency model late in a language's life splits the ecosystem. Most existing packages ar…

Yeah, my biggest complaint personally is that combining multithreading and async is a massive pain in the ass. Now, realistically, you aren't usually going to want to do that, except if you have multiple event loops, or are bridging between external synchronous code and internal async code. Otherwise, I really enjoy async python -- of course, I'm also the kind of person who has written my own event loops using synchronous code before, so maybe I'm just crazy like that.

Re: Making 1M requests with Python-aiohttp

#13
post #10

1,000,000 requests in 52 minutes is just 320 req/sec. Am I missing something? What's so amazing about this? I just deployed some production feed that serves at 1955 requests/second on a cheap VPS in freaking PHP, one of the slowest languages out there.

Why you say is not amazing? Honestly curious here :)

Because it's trivial.

I would be interested in anything doing 10,000+ req/sec on a cheap VPS. 320 is nothing.

People achieve 2 million requests/second with C++ on EC2:

https://medium.com/swlh/starting-a-tech-startup-with-c-6b5d5...

Re: Making 1M requests with Python-aiohttp

#14
I really keep wishing that there would be benchmark comparisons of asyncio/aiohttp with gevent/python2 . Performance would be a killer reason to migrate immediately to Py3.

What I suspect though is that asyncio is not all that better than gevent. Can someone correct me on this?

Re: Making 1M requests with Python-aiohttp

#15
post #8

Earlier quoted context omitted.

I guess I don't know how JS was any more "designed for" async than python was.

From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Even... : JavaScript has a concurrency model based on an "event loop". This model is quite different than the model in other languages like C or Java. ... A very interesting property of the event loop model is that JavaScript, unlike a lot of other languages, never blocks. Handling I/O is typically performed via events and callbacks, so when the application…

>>JavaScript, unlike a lot of other languages, never blocks

I think that's a little strong. It's more like "The group controlling Javascript has mostly tried to discourage introduction of things that block".

You can, for example, do a blocking XMLHttpRequest. It's deprecated, but possible. https://jsfiddle.net/923d5sda/

Re: Making 1M requests with Python-aiohttp

#16
I have a library for doing coordinated async IO in python that addresses some of the scheduling and resource contention issues hinted out in the later part of this post. It's called cellulario in reference to containing async IO mechanics inside a cell wall..

    https://github.com/mayfield/cellulario
And an example of using it to manage a multi-tiered scheme where a first layer of IO requests seeds another layer and then you finally reduce all the responses..

    https://github.com/mayfield/ecmcli/blob/master/ecmcli/api.py#L456

Re: Making 1M requests with Python-aiohttp

#17
post #10

Earlier quoted context omitted.

Why you say is not amazing? Honestly curious here :)

Because it's trivial. I would be interested in anything doing 10,000+ req/sec on a cheap VPS. 320 is nothing. People achieve 2 million requests/second with C++ on EC2: https://medium.com/swlh/starting-a-tech-startup-with-c-6b5d5...

Oh I see now... This speaks by it self:

C++/Proxygen =1,990,130 requests per second

Python/Tornado = 41,329 requests per second

Thanks for sharing btw

Re: Making 1M requests with Python-aiohttp

#19

Does anyone enjoy doing async work in python? I've done a few hobby projects and honestly I was yearning for javascript + async lib after awhile. As great as python is maybe we should yield async programming to the languages designed for it?

I think async and aiohttp are game changes for Python 3.5. After working with Twisted callbacks for over a decade, it's a pleasure to write async code that does not use the callback approach (granted Twisted is a mature environment with lots to offer).

I've switched to Python3.5 and aiohttp for all new web service applications. The coding style is clean, enjoyable to write, and easy to debug.

Plus, I've never once been stymied for speed. I know there's applications out there where people expect to to be handling zillions of connections -- but the bulk of my use cases think 100 transactions per second is a huge through-put, and aiohttp handles that with ease.

Re: Making 1M requests with Python-aiohttp

#20

1,000,000 requests in 52 minutes is just 320 req/sec. Am I missing something? What's so amazing about this? I just deployed some production feed that serves at 1955 requests/second on a cheap VPS in freaking PHP, one of the slowest languages out there.

I don't care for PHP as much as the next guy, but it's usually in the top 25 of the web framework benchmark (most of the other top langs are Java, Go and C++): https://www.techempower.com/benchmarks/
Post reply on HN