[HN Gopher] Asyncio, twisted, tornado, gevent walk into a bar
       ___________________________________________________________________
        
       Asyncio, twisted, tornado, gevent walk into a bar
        
       Author : BiteCode_dev
       Score  : 73 points
       Date   : 2023-08-22 17:56 UTC (5 hours ago)
        
 (HTM) web link (www.bitecode.dev)
 (TXT) w3m dump (www.bitecode.dev)
        
       | westurner wrote:
       | Eventlet (Linden Labs) actually owns the bar, then.
       | 
       | Edit
       | 
       | Green threads > Green threads in other languages:
       | https://en.wikipedia.org/wiki/Green_thread#Green_threads_in_...
       | 
       | Coroutine > Comparison with > Threads, Generators:
       | https://en.wikipedia.org/wiki/Coroutine#Implementations_for_... :
       | 
       | > _Generators, also known as_ semicoroutines _, [8] are a subset
       | of coroutines. Specifically, while both can yield multiple times,
       | suspending their execution and allowing re-entry at multiple
       | entry points, they differ in coroutines ' ability to control
       | where execution continues immediately after they yield, while
       | generators cannot, instead transferring control back to the
       | generator's caller.[9] That is, since generators are primarily
       | used to simplify the writing of iterators, the yield statement in
       | a generator does not specify a coroutine to jump to, but rather
       | passes a value back to a parent routine._
       | 
       | > ( _However, it is still possible to implement coroutines on top
       | of a generator facility_ )
       | 
       | Asynchronous I/O > Forms > Light-weight processes or threads:
       | https://en.wikipedia.org/wiki/Asynchronous_I/O#Light-weight_...
       | 
       | Async/Await > History, Benefits and criticisms:
       | https://en.wikipedia.org/wiki/Async/await
        
         | wahern wrote:
         | > That is, since generators are primarily used to simplify the
         | writing of iterators, the yield statement in a generator does
         | not specify a coroutine to jump to, but rather passes a value
         | back to a parent routine.
         | 
         | Another term for this asymmetric coroutine, as opposed to
         | symmetric coroutine. Coroutines in Lua are asymmetric, but
         | they're not generally referred to as generators as they're much
         | more capable than what are called generators in other
         | languages, like Python. This is largely because Lua's
         | coroutines are stackful rather than stackless, which is an
         | orthogonal, more pertinent dimension when implementing
         | concurrency frameworks.
         | 
         | You can implement symmetric coroutines using asymmetric
         | coroutines, and vice versa, by implementing a higher-level
         | library that implements one using the other. So in principle
         | they have equivalent expressive power, formally speaking.
         | Ultimately the distinction between these terms, including
         | generator, comes down to implementation details and your
         | objective. And just because a language name-drops one of these
         | terms doesn't mean what they provide will be as useful or
         | convenient in practice as a similarly named feature in another
         | language. Other dimensions--stack semantics, type system
         | integration, etc--can easily prove the determining factor in
         | how useful they are.
        
       | Waterluvian wrote:
       | I love how I read the setup, then clicked on the comments and got
       | the punchline delivered perfectly by Hacker News:
       | 
       | "We're having some trouble serving your request. Sorry!"
        
       | butz wrote:
       | Took me a while to figure out that real content of the website
       | hides under whole page covering popup.
        
         | BiteCode_dev wrote:
         | Damn, I explicitly disabled the subscribe wall in the settings.
         | WTF?
        
       | shanemhansen wrote:
       | Great article. I had the misfortune of writing a bunch of twisted
       | code over a decade ago and I wanted to remind the author that
       | twisted has a feature called "inline callbacks" that allow you to
       | use yield. https://twisted.org/documents/16.4.1/core/howto/defer-
       | intro....
       | 
       | So twisted code can actually look like:
       | @inlineCallbacks         def doIt():             responseBody =
       | yield makeRequest("GET", "/users")
       | returnValue(json.loads(responseBody))
       | 
       | iirc `returnValue` throws an exception of a specific type. It's
       | ugly, but it's also the logical implementation of async on top of
       | yield/generators.
        
         | BiteCode_dev wrote:
         | Also, asyncio started like this as well.
        
         | [deleted]
        
         | plq wrote:
         | returnValue raises a specific exception that inlineCallbacks
         | understands and translates to a normal return value. It was a
         | hack that was only needed for python versions that couldn't
         | have generators return non-None values. With modern versions,
         | you don't need it anymore -- just use return.
        
         | zokier wrote:
         | While inlineCallbacks exists, and indeed works, I would
         | recommend not using it. I recall it not interacting with mypy
         | particularly well, and in general being such a hack it had some
         | annoying sharp edges. Explicit callbacks might be annoying but
         | at least they are extremely clear on what's happening.
        
       | Fizzadar wrote:
       | Really good write up. Been using gevent in pyinfra[1] for years
       | and swear by it. Had some pains with setup, and am usually very
       | wary of such magic, but it's just really solid. Mostly write go
       | these days though which has taken the shine off for sure!
       | 
       | Twisted, however, is a different beast. Have spent s decent chunk
       | of time working on Matrix synapse homeserver[2], written in
       | twisted, and oh my it just sucks.
       | 
       | [1] https://github.com/Fizzadar/pyinfra
       | 
       | [2] https://github.com/matrix-org/synapse
        
       | zokier wrote:
       | I struggle to call fastapi a microframework, or even bundle it in
       | the same category as flask. Starlette, the actually small
       | framework at the core of fastapi, fits the description better and
       | would have deserved a mention imho.
        
         | throwmeout123 wrote:
         | But its also not a framework as it offers barely any facilities
         | for mid+ size projects, which immediately start to crack under
         | the weight of trying to reimplement Django
        
       | BiteCode_dev wrote:
       | _Summary_ :
       | 
       | Concurrency has a lot to do with sharing one resource, and Python
       | has dedicated tools to deal with that depending on the resource
       | you must share.
       | 
       | If you have to share one CPU while waiting on the network, then
       | the specialized tools for this are asyncio, twisted, trio,
       | gevent, etc.
       | 
       | Asyncio is the current standard to do this, but tornado, gevent
       | and twisted solved this problem more than a decade ago. While
       | trio and curio are showing us what the future could look like.
       | 
       | But chances are, you should use none of them.
        
         | bch wrote:
         | > But chances are, you should use none of them.
         | 
         | So, no event-oriented programming in Python, or by some other
         | mechanism, or...?
        
           | js2 wrote:
           | From the conclusion of the article:
           | 
           | > If you need to get a few URLS fast, a ThreadPoolExecutor is
           | likely the Pareto solution, 99% of the time.
           | 
           | I agree with this. ThreadPoolExecutor is easy to use. In
           | general, using threads in Python to handle concurrent I/O is
           | pretty simple and plenty performant.
        
       | jononor wrote:
       | I picked gevent for a greenfield backend (in IoT/ML space) back
       | in 2019. No regrets. The main contender was asyncio, which was
       | the hot-new-thing at the time (still is, I guess). At the time, I
       | did not feel that the ecosystem and programming practices for
       | asyncio were good enough. That has of course matured a lot now,
       | so it is no longer an issue. But I would actually still consider
       | gevent again for a new project today. Possibly the asyncio web
       | frameworks (ie FastAPI) have the edge over gevent-compatible (ie
       | Flask) though, which might tip the scales.
       | 
       | I remember using Twisted some 10 years ago. Never again...
        
       | whalesalad wrote:
       | gevent is the way to go these days tbh. asyncio is close but the
       | dependency on async-aware libraries can be problematic.
       | 
       | surprised the author ended on the note that none of these are
       | relevant - i use a lot of these tools on a weekly basis.
        
       | plq wrote:
       | Here's the said black magic (for amd64/unix) that the gevent
       | project relies on:
       | 
       | https://github.com/python-greenlet/greenlet/blob/master/src/...
       | 
       | I still think it's too much for a Python project -- if you think
       | you need this in 2023, maybe you need to reevaluate? I'd
       | seriously have another look at Go.
        
         | Blackthorn wrote:
         | That's surprisingly readable and understandable. Nice work by
         | the authors for encapsulating it so well.
        
         | d1l wrote:
         | All greenlet does is allow the Python frames to managed
         | separately from the C call stack - it is very similar to what
         | Pypy is also doing. I don't think your characterization is at
         | all accurate.
        
       | [deleted]
        
       | DishyDev wrote:
       | Great write up on something I depend on a lot but don't
       | understand well.
       | 
       | This also answers something I've always wondered about which is
       | how Twisted and Tornado fit into the Python web framework
       | landscape and whether I should use them. Tornado always seemed
       | popular but slow and less intuitive than Flask/Django. And then
       | Twisted was a far lower level library but people were still
       | building APIs on it.
       | 
       | Where does Eventlet fit into the picture? Is it a similar box of
       | magic monkey patches like GEvent?
        
       | sigmonsays wrote:
       | ever look at a twisted stack trace?
        
         | BiteCode_dev wrote:
         | And worse, when you do, something loop back.
        
       ___________________________________________________________________
       (page generated 2023-08-22 23:00 UTC)