7 ms·
> we make heavy use of asyncio because it’s more performant more performant than....what exactly? If I need to load 1000 rows from a database and splash them
by zzzeek 10y ago
> we make heavy use of asyncio because it’s more performant
more performant than....what exactly? If I need to load 1000 rows from a database and splash them on a webpage, will my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms? Answer: no. async only gives you throughput, it has nothing to do with "faster" as far as the Python interpreter / GIL / anything like that. If you aren't actually spanning among dozens/hundreds/thousands of network connections, non-blocking IO isn't buying you much at all over using blocking IO with threads, and of course async / greenlets / threads are not a prerequisite for non-blocking IO in any case (only select() is).
it's nice that uvloop seems to be working on removing the terrible performance latency that out-of-the-box asyncio adds, so that's a reason that asyncio can really be viable as a means of gaining throughput without adding lots of latency you wouldn't get with gevent. But I can do without the enforced async boilerplate. Thanks javascript!
- tyingq 10y agoHeh. Somebody will assemble a few of these pieces, add a package manager for async oriented libs, call it node.py, and then market it a bit. Then you'll really be irritated.
- merb 10y agowell it can also make things faster. well in your example it won't. but consider you need to load 4 requests and do operations on each of them. if you schedule them in an async fashion you can begin operating on the first one that's ready and not the first one you defined. and this is also often the case. a website does not just do one request to the database. mostly it runs multiple ones and often they don't interfere. like getting 20 rows and the count as a whole, there is just no need to start the first and wait till you have 20 rows and then start the second. you should always start both and wait till you have both. yes it does not magically make your fetching 100 rows faster or your pbkdf2()/bcrypt() function. you still need to wait for those.
- zzzeek 10y ago> if you schedule them in an async fashion you can begin operating on the first one that's ready and not the first one you defined. This type of operation is a given in any production quality webserver, whether it runs with multiple threads and blocking IO or using a non-blocking approach with greenlets. For a web application, this is an implementation detail that should not be explicit within the request handling code (a request handled in the context of a web container after all is a package of data in, a package of data out. no network reading/writing is usually exposed to the web application unless it's trying to expose IO handles to the app, which is unusual). Easy enough with something like Gunicorn.
- icebraining 10y agoI think you're talking about different things; the idea is not that you can multiplex the requests coming in, but also the requests going out to the database and etc for each web request handling function.
- zzzeek 10y agoSo on that topic, a request typically has a single transaction going out to the database so within the scope of the request, has to perform its steps in serial in any case. If it needs to make several requests to web services that aren't dependent on each other, that's an area where you can get into stacking them with some kind of concurrency construct (I'd pass it into a greenlet oriented worker pool). but this is already going to be a heavy web request with multiple web service calls.
- kazagistar 10y ago> a request typically has a single transaction going out to the database Its typical because people are still in a "single thread single transaction ORM crud" model of thinking. "Its linear because thats how it is"?
- 10y ago
- bysin 10y agoI'm glad you said this. There's an async cargo cult going on, where every service must be written in "performant" async code, without knowing the actual resource and load requirements of an application. From the last benchmark I ran [1] async IO was insignificantly faster than thread-per-connection blocking IO in terms of latency, and marginally faster only after we hit a large number of clients. Async IO doesn't necessarily make your code faster, it just makes it difficult to read. [1] http://byteworm.com/evidence-based-research/2017/03/04/comparing-the-performance-of-synchronous-versus-asynchronous-network-io/ http://byteworm.com/evidence-based-research/2017/03/04/compa...
- tuxracer 10y agoconst users = await getUsers(); const tweets = await getTweets(users); console.log(tweets); Is async code really harder to read?
- paulddraper 10y agoThrow an exception and look at the stacktrace.
- akst 10y agoThis looks pretty readable to me https://repl.it/H547/2 https://repl.it/H547/2
- paulddraper 10y agoSorcery. Why don't my JS stacktraces look nice? :(
- WorldMaker 10y agoDepends on you dev environment. Almost all of the browser dev tools should catch up eventually. The fun of an ecosystem with multiple competing implementations.
- 10y ago
- flukus 10y ago> more performant than....what exactly? If I need to load 1000 rows from a database and splash them on a webpage, will my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms? Potentially, it depends on if you can do other tasks for the same request that don't depend on the data. You might be able to render most of the page for instance. It's not purely about throughput. Please tell me that 300ms was made up too and that it's not really taking that long.
- matthewaveryusa 10y agoIt buys you the stack size of each thread which only matters if you have a stupid amount of connections. In this article[1] the author makes a comparison between the 2 models and 7000 concurrent users will chew up 450MB of stack space. Of course this is adjustable. [1] http://byteworm.com/evidence-based-research/2017/03/04/comparing-the-performance-of-synchronous-versus-asynchronous-network-io/ http://byteworm.com/evidence-based-research/2017/03/04/compa...
- davesque 10y agoHow do you save on stack space with asyncio? Don't you have to keep the coroutine object in memory somewhere?
- bschwindHN 10y agoI think the idea is that these "coroutine objects" (or the equivalent structure in whatever language) is smaller than the typical stack size for a thread. For example, the default stack size on Windows is 1 MB. So if you have a thread per connection, obviously this is going to take up a decent amount of memory. I'm guessing the answer to this is a thread pool so your memory usage doesn't blow up. https://msdn.microsoft.com/en-us/library/windows/desktop/ms686774(v=vs.85).aspx https://msdn.microsoft.com/en-us/library/windows/desktop/ms6...
- hawski 10y agoOn most Linux systems stack is allocated with mmap with overcommiting. Until first write all those pages will share same zeroed page AFAIK. Then only overwritten pages will be allocated. Am I wrong?
- est 10y ago> If I need to load 1000 rows from a database and splash them on a webpage, will my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms? Answer: no Well, actually, yes. Without async rendering, your webpage is not ready until your 1000 rows of list is placed in Python memory then rendered to HTML as a whole then returned to your browser after like 300ms of server cost. With async rendering, your webpage's headers and such can be returned immediately, thus your first-byte-to-response time can be done under 50ms, and your page loads by enumerating the rest of 1000 rows and renders the page incrementally.
- zzzeek 10y agoThat's a client streaming optimization, not related to the subject at hand which is non-blocking network IO. Assume the service returns a JSON structure. It won't get to the end any faster.
- est 10y agoThere must exists a module like `ijson` which could incrementally generate JSON.
- makmanalp 10y agoI went down this rabbithole once, and turns out you /can/ do something like this, having everything streaming all the way from the database to python to the web server to the client. The problem then was that even after all that effort, whatever javascript usually was processing that in a non-streaming way. Then I found this http://oboejs.com/ http://oboejs.com/ and it was even more work, and I gave up. In the end it required rethinking everything and battling against a whole set of tools and libraries that just didn't think that way.
- RubyPinch 10y agoWell you can do all of that sync, can't you? def on_connection: send(headers) send(start of page) for row in db: send(row) send(footer) will have the exact same effect as what you said (not like that applies regardless, I don't think jinja outputs partial renders, since its made for flask) The performance comparison is between python managed green threads, and OS managed actual threads. You don't get any new features
- RubyPinch 10y agohttps://magic.io/blog/uvloop-blazing-fast-python-networking/http-bench.html https://magic.io/blog/uvloop-blazing-fast-python-networking/... from the makers of uvloop (for a toy example) it seems the main bottleneck when using aiohttp is aiohttp itself, which practically makes the use of uvloop irrelevant
- ma2rten 10y agoWill my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms If you have to do 1000 queries it could, since could async will make it feasible to do them parallel. If it's a single query, maybe async would make it feasible to shard the database.
- manquer 10y agoyou usually see this pattern in ORMs with n+1 querys . If a single request requires 1000 db queries it is better to be optimising the query
- Dowwie 10y agoYou are the hero we need, Mike
- anentropic 10y agoIf you have to make several requests to db backend to fulfil one response then potentially asyncio allows you to make them in parallel rather than in series. Reducing latency of your response.