For Python, you can get the benefits of asynchronous IO without callback hell if you use the Stackless fork.
A similar idea for Node is node-fibers.
Both let you build exception-safe coroutines.
For Python, you can get the benefits of asynchronous IO without callback hell if you use the Stackless fork.
A similar idea for Node is node-fibers.
Both let you build exception-safe coroutines.
On top of that, gevent outperforms both twisted and tornado because the eventloop is libev, meaning it's written in C instead of pure python.
To be clear: gevent is significantly faster than eventlet and offers the same functionality.
- It can't use multiple cores, even if Python got the ability in the future, gevent code simply wouldn't work as intended.
- While gevent is not preemptive, context switches are implicit, that means you cannot write code without locks unless you want to do some handwaving. You have to know the entire system to know that a multistep operation that calls functions is actually safe.
On the net, gevent may be better than Twisted or Tornado, but I think that is saying more about how much those suck than how good gevent is.
It is intended to create an environment similar to preemptive threads, yet due to it being a networking library it is unlikely gevent users will have to use the semaphore and locking primitives provided with gevent.
Regarding the weaknesses of callbacks, I disagree and would like to see evidence supporting your case.
> - It can't use multiple cores, even if Python got the ability in the future, gevent code simply wouldn't work as intended.
This is pure speculation. If Python's multicore handling was better (existed?), it's likely gevent would be implemented similar to other systems where you have threads allocated to each core and the concurrency primitives can then be executed on cores according to some algorithm.
> - While gevent is not preemptive, context switches are implicit, that means you cannot write code without locks unless you want to do some handwaving. You have to know the entire system to know that a multistep operation that calls functions is actually safe.
While this is true, I don't think it is likely to occur. Gevent's creator agrees: http://www.gevent.org/intro.html#cooperative-multitasking
> On the net, gevent may be better than Twisted or Tornado, but I think that is saying more about how much those suck than how good gevent is.
You're an Erlang programmer. You have to have that opinion.
(sausagefeet and I are friends IRL so I know his biases)
The weakness of callbacks is the lack of multicore support. It is not pure speculation that gevent simply won't work in a preemptive environment if it wants to utilize multiple cores. The sentence right about this makes my point:
> yet due to it being a networking library it is unlikely gevent users will have to use the semaphore and locking primitives provided with gevent.
Why is that? It's because gevent context switches on I/O events, not preemptively, so you have some control over when context switches happen. You can depend on 'my_dict[foo] += 1' to happen atomically. If you want to utilize multiple cores with gevent, as code using it is written now, you can't because all of the code out there depend on operations between I/O events happening atomically. This isn't a secret in the callback/gevent world. On the contrary, it's presented as a selling point. No longer worry about those locking primitives those real threading libraries give you because we are single threaded. (Ocaml/Lwt has the same problem).
> While this is true, I don't think it is likely to occur
I'll concede it's far less likely. I'm curious how large gevent code bases are in the wild, a large application that one cannot fit in their entire head could very well have a lot of the same race conditions that a preemptively threaded application has.
> You're an Erlang programmer. You have to have that opinion
Really? I didn't realize when I started using Erlang I signed a contract saying that. I also write Ocaml, so I guess any criticism I levy against Java is a product of that too, not rational thought.
You suggest that gevent won't work in preemptive environment if it wants to support multiple cores, alas I'm still not convinced as to why.
The greenlets are cooperatively scheduled coroutines, as we know, but with proper multicore support I don't see why they couldn't adapted to be preemptively scheduled. If we're imagining that Python now has multicore support, we can also imagine greenlets being updated to work with it. Assuming gevent would receive no modifications to work with such an important update to Python is why I accused you of speculating.
> It's because gevent context switches on I/O events, not preemptively, so you have some control over when context switches happen.
That's correct. They are cooperatively scheduled coroutines. If someone wants to context switch, they can write code that does it or wait for I/O events. The lack of an explicit yield statement does not prevent coroutines from switching. In fact, greenlets are quite powerful here, more powerful than what's offered by Twisted and Tornado, because they don't have to yield directly to the caller. You could imitate CPS which is impossible with the explicit context switch model.
I am not disagreeing with you on this point, btw, just trying to be more explicit for other readers about the cooperatively scheduled nature.
Interested readers might want to check this out: http://en.wikipedia.org/wiki/Computer_multitasking#Cooperati...
> I'm curious how large gevent code bases are in the wild
Well, eventlet itself was written to support Second Life and sits behind multiple big video games.
Gevent is in production use for many large companies, most notably Spotify. They are moving to gevent from twisted for performance and cleaner code.
> I didn't realize when I started using Erlang I signed a contract saying that. I also write Ocaml, so I guess any criticism I levy against Java is a product of that too, not rational thought.
My statement is facetious, but the reality is that Erlang got concurrency right and Python is trying to glue concurrency ideas into the language as an afterthought. If Python didn't have it's lousy GIL we wouldn't have to pull such tricks to work concurrency into a single threaded system. Alas, it has the GIL.
Now, to conclude some of my thoughts, I believe gevent is an excellent way to build web systems. The coroutines are short-lived, exist to fetch some data with an easy nonblocking interface and then concat some strings together to produce the web page / API output.
If folks were building CPU bound systems it would straight-up be a mistake to use Python for that. Ocaml could be a better choice, alas, as you say, it has the same issue with a GIL though the computations would execute a LOT faster.
Edit: Solve the problems you actually have.
I hope this conversation is informative for readers.
UI programming is callback heavy, but I doubt that any language will support "better" ways for that.
So basically UI programmers are used to callbacks, others not that much, and now that event-loop servers are becoming popular, we see confusion from people not familiar with events.
Server-side people just need to figure out how to use callbacks properly and everything is gonna be fine.
All people need to understand is to nest callbacks properly, nested callbacks are the things that confuse most people.
> For Python, you can get the benefits of asynchronous IO without callback hell if you use the Stackless fork.
You can't just abstract away every programing feature that seems hard and expect everything to be fine, it just doesn't work that way, Java developers are still suffering because Java tries real hard to abstract memory management.
I wonder why you mean by using callbacks properly ? The critical point mentioned by Guido is error/corner-case handling: the idiomatic callback-based code I have seen becomes difficult very quickly. I have not seen a case where e.g. deferred-based code ala twisted has been simpler than gevent.
I don't think that's right. There is a huge difference. UI callbacks ("onClick" and the like) execute synchronously. But the callbacks in event servers execute at completely different times. Indeed, they're typically nested inside code that has long since terminated. This is what causes the learning curve, not grokking events or functions-as-values, which any half-decent programmer can easily do in the unlikely event that they didn't a long time ago. Indeed, the way we write asynchronous callbacks is cognitively dissonant with everything we've been trained to understand about scoping. The idea of a nested scope that doesn't mean "contained within" or "covered by", but rather "at some unknown time later", is inconsistent enough with how programming languages normally work that it can easily trip you up even after you get good at it.
Asynchronous programming is a very different thing than e.g. browser UIs in Javascript. I've programmed those for years. It still took me a long time to get my head around async servers.
Rob Pike designed one of the spiritual ancestors of Go, Squeak ( http://doc.cat-v.org/bell_labs/squeak/ ) using the CSP model of concurrency specially to build (G)UIs.
Nobody particularly likes reading callbacky code, but it has a lot of power. What we don't have enough of is "structured alternatives" for our "goto."