4 ms·
I get that SA ORM is unfit to run on the eventloop thread, but I’m increasingly unclear if you hold your position that asyncio is bad solely because it makes SA
by dfee 8y ago
I get that SA ORM is unfit to run on the eventloop thread, but I’m increasingly unclear if you hold your position that asyncio is bad solely because it makes SA ORM less competitive - and less of a ecosystem standard.
The alternative being just using SA Core and something like aiopg, using asyncpg, or using SA in a threadpool (unfortunately, a technique that’s involved enough that the recipe for using SA isn’t a 5 min “gotcha”, re: flask).
I like SA. I’ve used it for years, and you’ve helped me on the forums, so I’m appreciative for the work you’ve done. I just don’t understand why you’ve written off an entire style of programming.
- zzzeek 8y ago> but I’m increasingly unclear if you hold your position that asyncio is bad solely because it makes SA ORM less competitive - and less of a ecosystem standard. It's not that the ORM is less "competitive" because I am certainly able to make an async version of SQLAlchemy, it's just I don't have the time / interest / resources to do so, and as I've gone through the effort to write about in detail, it is a bad idea. If you want to pay me a salary to make an async SQLAlchemy I can totally do that. It would be a worthwhile effort in that it would make people happy. But also it would be a wasteful effort in terms of advancing the field of Python database programming. That's the decision I'm facing and it would be a lot easier if folks would just realize asyncio isn't getting them much overall. It's like, suppose I make bikes. But everyone wants to get to work on pogo sticks instead. Everyone who uses pogo sticks is terminally late to work, they're getting injured all the time, they are miserable, but someone told them "hey pogo sticks are FASTER than bikes!", people were just bored with bikes so much that they didn't even bother testing this assertion, and now everyone just has discussions like "oh well I have this shiny new pogo stick, so I only broke three ribs this week! hooray!" and people have just forgotten that there is nothing wrong with bikes at all and they are in fact a lot better than pogo sticks for the task of getting to work every day (you might find pogo sticks to be more interesting and fun in the moment, but as a real solution to the problem, they are not any better than bikes and probably worse). Someone who makes bikes tries to point all of this out. That puts you in the position of saying, "all your arguments about bikes being better than pogo sticks for getting to work, who cares. you are just concerned pogo sticks are a threat to your bike sales". Well, yes, they are. But the bigger issue is that it is ridiculous everyone is killing themselves trying to get to work on pogo sticks. Somehow I feel that should not be lost. > I just don’t understand why you’ve written off an entire style of programming. I've written and tweeted about this a lot so feel free to point out the reasons that might not be clear. To recap http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/ http://techspot.zzzeek.org/2015/02/15/asynchronous-python-an...: asyncio is essentailly intended to provide an interface around the concept of non-blocking IO. The relational database use case, for the vast majority of uses (e.g. CRUD), gains nothing from using non-blocking IO (most databases don't even offer a non-blocking API anyway) and only complicates the application, introduces subtle bugs, and does not improve performance. The other argument made about asyncio is that replacing the OS'es task scheduler with a cooperative one defined by when IO happens to occur is "safer", because context switches are no longer implicit. The second section of the post above makes many arguments why this is not the case and especially not for modern server-side application design which is inherently multi-process.
- devxpy 8y agoTHANK YOU
- c0un7d0wn 8y agoComing from nhibernate now working with sqlalchemy, more so than async the one feature i miss when working with sqlalchemy is futures with multiple result queries, like this https://ayende.com/blog/3979/nhibernate-futures https://ayende.com/blog/3979/nhibernate-futures
- dfee 8y agoI don’t know, an asyncio ORM version seems very challenging, but if anyone could do it, it’d be someone with deep domain knowledge (like you). Relationships as properties for example, I just don’t know how you’d solve attribute access in an idiomatic way (sure it could return a future, so maybe the idea is that you’d get a future subclass that still supports operations)? Anyway, the problem is that it’s really difficult to mix sync/async code. And as soon as you’ve got a need for websockets, you’re pretty much thrown into the world of asyncio. To use the ORM is then a threadpool issue. Anyway, my approach has instead been to use SA Core (with aiopg). I’ve probably always gotten to involved with my Mappers anyway.
- zzzeek 8y ago> Relationships as properties for example, I just don’t know how you’d solve attribute access in an idiomatic way (sure it could return a future, so maybe the idea is that you’d get a future subclass that still supports operations)? I think the answer would be that you just ditch "lazy loading" altogether, in the spirit of asyncio's theme that "implicit IO is bad", you'd have to have explicit conversations with the DB. Loading attributes from relationships is one thing, but there's also the notion that other kinds of attributes can refresh themselves if they happen to have been expired, which is something the ORM does when a server-side rule or a transaction boundary that might mean the attribute changes on the database side. It's a very elegant and simple solution to the problem but if you have decided that implicit IO is bad, it means you don't really want that anymore. You'd just start treating an ORM mapped object more like an active row and you'd have yields on most operations, and you'd also want to add more coarse-grained boundaries to when state is expired and re-loaded (e.g., instead of expiring particular attributes as needed to be reloaded when accessed, there would need to be a more formal "refresh the object" kind of step). That's one way to do it. Another way would be if an implicit non-blocking approach such as gevent could be cleanly integrated with asyncio - then object heavy database interactions could simply be inside of a block written in "blocking IO" style, and that entire block is entered as a yield. There is no technical reason this can't be done. The reason is cultural; people who like asyncio really hate implicit IO. So trying to make that work seems like it wouldn't be very worth it either. > Anyway, the problem is that it’s really difficult to mix sync/async code. I think this is because people just aren't working on the problem. You read asyncio tutorials and they say things like, "if you really MUST use evil threads...here's this crappy executor thing we think you should never use", I'm exaggerating a bit but that's kind of the vibe they send off. Making the asyncio / thread transition could be done very nicely, and there can also be integrations between gevent style and asyncio style, and finally there are many other ways to use non-blocking IO without using a full event style programming interface. The asyncio crowd isn't there yet. They are still having the endorphin high of asyncio "clicking" for them and they are rigidly dogmatic and pretty short on real benchmarks that show actual gains. I have nothing against using non-blocking IO but the next time I have to use it, I'm going to purposely build a non-blocking IO library that seamelessly makes use of threads and queues and shows how easy it is if you really need to reach out to a dozen slow web services at once to get the non-blocking IO advantages without turning your entire codebase and dependencies inside out. > Anyway, my approach has instead been to use SA Core (with aiopg) right, so another thing to keep in mind, Postgresql is the only database that has a native non-blocking protocol. So building an async ORM is immediately limited by that - for every other database there would still be a threadpool running the socket conversation, and having every database message be a separate threaded unit is less efficient than just having the entire transactional conversation in one threaded unit (hundreds or thousands of shifts in and out of the thread pool vs. just one). There's really many reasons to not write an asyncio ORM right now.
- BerislavLopac 8y ago> I just don’t understand why you’ve written off an entire style of programming Async(io) is not a "style of programming"; it is an approach to solving a certain class of problems which arise undercertain conditions, and is only really useful if it fits your use case. I'm certainly happy that Python has introduced it on a low level, but I definitely won't use it in situations that don't warrant it -- the same holds true for many other Python idioms, like say ABCs or Ellipsis.
- dfee 8y agoI’m not going to debate on the definition of the word “style”. Yeah, I see it as an alternative concurrency model to threads. And I think each has its pros. As for you not using it in situations that don’t warrant concurrency, that’s a good idea.