4 ms·
> but instead people are re-inventing 'sqlalchemy' SQLalchemy last version is asyncio compatible now: https://docs.sqlalchemy.org/en/14/orm/extensions/asynci
by BiteCode_dev 5y ago
> but instead people are re-inventing 'sqlalchemy'
SQLalchemy last version is asyncio compatible now: https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.htm...
> network libraries and entire web frameworks for the sake of two new keywords
The trend in the community now is SansIO: https://sans-io.readthedocs.io https://sans-io.readthedocs.io
You create entire libs without the IO parts, dealing only with the business logic.
The you let the I/O libs to deal with the rest. This allows modern project to provides a sync and async API with the same protocol implementation. E.G: https://github.com/encode/httpx https://github.com/encode/httpx
Also, I'm pretty glad gevent has not been adopted:
- it's very hard to know if you are doing something wrong with gevent. Or doing something with gevent at all.
- gevent magic patching broke stuff in unpredictable ways, and the solution was to disable part of it: https://stackoverflow.com/questions/8678307/gevent-monkeypatching-breaking-multiprocessing https://stackoverflow.com/questions/8678307/gevent-monkeypat...
- gevent didn't play well with stdlib threads and multiprocessing, (had its own thread pool, subprocess wrapper, and no multiprocess story) while asyncio has a very good interoperability story
- the asyncio pluggable loop meant we didn't need a perfect solution out of the box. Thanks to that design, we have been able to integrate the nodejs loop, like with the uvloop project, giving birth to stuff like asgi, fastapi and uvicorn. Asyncio can now comparable async perfs as Go. (gevent does that, but forces you to, and having libuv in the stdlib is not something the core devs would want).
- gevent is a 5mo package. It's 1/6 of the ENTIRE python installer.
- the coroutine based design means we have a standard api for async, no matter the backend or implementation. Which means solution like trio were able to emerge, and eventually the core dev are now considering including trio-like scoping in the next asyncio iteration.
There are plenty of problems with asyncio though:
- create_task is basically a goto. See trio for a solution.
- coro() does not run the coro task. In JS it does, and returns a future you can await, or not. This makes it very confusing to beginner that get lost in the await/return/create_task dance.
- there is no concurrency limiting primitive, cancellation is hard and back pressure mitigation is non existent.
I was very skeptical about asyncio, but after 3.7, it became quite nice. asyncio.run() made all the difference, ergonomically, and when dealing with errors.
- ghostwriter 5y ago> SQLalchemy last version is asyncio compatible now. it's been compatible for 5+ years already, Core API was driver-endependent even in 2015. > Also, I'm pretty glad gevent has not been adopted: When I say 'adopted' I mean integrated into the language runtime so that the entire stdlib is aware of it. Some of your points consider the state of gevent 10 years ago, that's not a benchmark for a conclusion on how successful a potential integration into the core language might be, and none of them point at inherent issues with the implementation that make it unusable compared to asyncio.
- BiteCode_dev 5y ago> , that's not a benchmark for a conclusion on how successful a potential integration into the core language might be That's fair. I'm also biased by the fact I really like to know when my code is suddenly going into async territory. I like the JS model for this: it's explicit enough that there is little surprise (promises are now a standard, so if something returns a promise, it's async), but implicit enough that I don't have to care (no loop to setup, no coroutine instantiation between calling and scheduling). And it aged well: future can now just be awaited, and you can simply keep the callback api in non async function. gevent is too implicit to my taste I guess. Now you could argue that we could make gevent calls explicit, but then it would be not that much different from asyncio. I would really be happy if the community would settle in something like: @autorun async def coro(): ... Then: coro() # this calls create_task(), and binds it to the upper nursery I think it would strike the right balance from a usability point of vue. As for the interoperability issue, it's a pretty though nuts to crack.
- ghostwriter 5y ago> - the coroutine based design means we have a standard api for async, no matter the backend or implementation. Which means solution like trio were able to emerge, and eventually the core dev are now considering including trio-like scoping in the next asyncio iteration. The structured API for concurrency that Trio provides, in principle, doesn't depend on the said keyword-based approach - it's just what the author chose to use for the implementation. It's definitely not something that asyncio enabled for its users that wasn't possible without it. Here's another structured API for concurrency that doesn't depend on keywords [1]. It can be implemented with gevent. [1] https://hackage.haskell.org/package/async-2.2.3/docs/Control-Concurrent-Async.html#g:high-45-level-45-utilities https://hackage.haskell.org/package/async-2.2.3/docs/Control...