Thanks to WSGI you can have projects like this that focus on scaling out your Python web all to the fullest extent possible.
Thanks to WSGI you can have projects like this that focus on scaling out your Python web all to the fullest extent possible.
It addresses one of the major shortcomings of CGI by not requiring to launch a new process for every request. 20 years later it is still going strong and is still by far the main way Python web apps are served.
As for FastCGI, although it is language agnostic it didn't really get traction outside of PHP.
Pro tip: WSGI is pronounced like "whiskey". :-)
The point of WSGI is for the server and application to speak the same python-level protocol. You can have a wsgi adapter on top of fcgi, though it’s really a waste of resources if you can skip fcgi entirely (which you usually can).
One of the initial inspirations for creating the Django web framework back a the Lawrence Journal-World newspaper in ~2003 was that we wanted to start using Python on the web, but were concerned that mod_python didn't have quite enough existing users.
What if it turned out not to work for us?
So we designed a simple abstraction layer - a request and response object - as an insurance policy. If mod_python turned out not to work for us we could switch to something else without having to rewrite all of our code.
At around about the same time the Python Web SIG formed - https://simonwillison.net/2003/Oct/18/pythonWebSIG/ - and we joined it with the aim of helping define a standard similar to what we had been building for our own, private newspaper CMS.
WSGI was the eventual result of that SIG - I didn't participate in the working group nearly as actively as I had planned to, so I can't say that I had much if any impact on the result.
But hopefully this illustrates that yes, the people involved were very aware of mod_python back in 2003 when this work kicked off.
PS That is why I love HN. You get to casually see creators of great projects.
Theoretically one could produce ready-to-run, guaranteed clean Python request handlers very quickly. Run all the startup and imports stuff in a Python process, then freeze it. Fork a copy of it on a new request (with COW it's definitely fast), and terminate it normally after that. This would require some care, e.g. to not open sockets before the fork, so that handlers won't share it.
I bet it has been tried, but I'm too lazy to actually search for that.
I believe wasmtime can be faster as it doesn’t need to create as many new OS resources and just resets some memory maps.
Only really meaningful for simple request handlers taking a few milliseconds.
Granian sounds interesting. I'm not sure how you deal with the "two async runtimes" problem tho. Essentially, if you do non-blocking IO, then your processes start to become CPU-bound. So granian can eat up CPU on high load, and leave little CPU for the asgi application (or vice-versa). Somehow that doesn't sound right, but I also can't think of how you'd solve that.
While it might sound "odd", actually having two runtimes running in two different threads is not so strange. This is actually what you end up when spawning multiple Python processes even with uvicorn: each process will have the asyncio event-loop running in the main thread.
In Granian the Python runtime and the Rust ones communicate with each other in a non-blocking way, so – theoretically speaking – there's no additional CPU-bound load compared to a pure Python solution.
Also, theoretically speaking, the only condition I can imagine where the two runtimes fight too much with each other is in case where you have a single core system with so poor performance to not handle 2 threads concurrently, which is probably so rare that we don't need to think about it..
Probably I should add some resource usage tests aside to benchmarks, but – again, theoretically speaking – if the Rust code is more efficient than the Python one, the final CPU usage should be lower, or more efficient.
My main confusion around this is: how do I scale threads? Say I have to CPU cores. Do you run one Granian thread and one python thread? I Granian under-uses CPU, Python can't use the excess. But if I run one Granian thread and two python threads, I risk Python leaving Granian with less CPU than it needs.
In practice it should not be hard to find a balance... but somehow I'm still bothered by the fact that the design has no obvious solution for this.
Unpacking the acronyms might help
ASGI may be new to some, but... how is it possible to do Python web development without first learning what WSGI is? I haven't done much Python dev but WSGI seems to be the standard way - what's the less optimal alternative that people might end up with?
You'll be surprised to find out that there are many software developers who are "fast learners", but actually are shallow learners. Or to put it more kindly, they are not-so-curious learners, i.e. they only learn just enough things they need to accomplish the task at the moment. It's not necessarily a bad trait; but sometimes if you don't learn the fundamentals, it will cost you more (time, effort) along the way.
A vast majority of people who call themselves "python devs" got there by copy-pasting ML scripts from stackoverflow (and now chatGPT) into jupyter notebooks.
Basic tutorials for Python newbies use wsgi. Copying & pasting from SO without understanding the code you're copying will inadvertently net you a wsgi setup. FastAPI requires wsgi.
I wasn't stating that everyone deploying Python has a depth of knowledge of wsgi - I was enquiring as to whether there's some other alternative system people pervasively use for Python web apps, as I assumed everyone was on wsgi (whether they're aware of it or not).
TL;DR: by "learning what wsgi is" I just meant "deploying it" not "understanding it in depth"