Python is not broken but works very well and helps people make millions all over the world.
Python is not broken but works very well and helps people make millions all over the world.
For instance, a local cache of some values is basically useless when python is used as backend. Since there will be multiple processes handling the requests (in the same node), they don't share memory. So basically everything has to be stashed at redis. Of course, with scale and multiple nodes lots of stuff should be cached in redis anyway. But not everything makes sense to reach out to an external service for. Like fetching a token I need to use multiple times, instead if having it stored locally in a variable. There are of course ways around this, using some locally shared file or mmap or whatever, but it's a hassle compared to just setting a variable.
Same with background tasks or spinning up extra threads to handle the workload of an incoming request. Can't easily be done, so basically every python project includes celery or something similar. Which works fine, but again, a different and forced way to solve something.
Asyncio solves many of the daily problems I would have used threads for, though. As I often used it other places to fire off some http requests to other services in parallel. But unfortunately async doesn't work properly with everything yet.
So everything has a solution, but you are forced to do it "the python way" and with some hurdles.
It was a cool idea that turned out not so be so great after all.
There is a reason why all major language runtimes are moving into thread agnostic runtimes, while security critical software and plugins are back into processes with OS IPC model.
Go in their typical wisdom, doesn't even support thread local storage.
Additionally, Java and .NET have thrown away their security managers, and guess what is the best practice to regain their features in Java and .NET applications?
Multi-processing with OS IPC.
But of course, for security address space separation is pretty much a requirement.
Obviously, you can choose to do it that way, but there is no reason that multiple processes can’t share memory in Python; there is, in fact, explicit support for this in the standard library.
> you can choose to do it that way, but there is no reason that multiple processes can’t share memory in Python; there is, in fact, explicit support for this in the standard library.
Yes, and you can also just use threads and directly go shared memory so you are not literally "forced", you are forced because the choice comes with a cost you don't want to pay. Depending on the OS for managing shared memory and using an API isn't much different from using a sidecar process and has its own cost over native shared memory model. In the end, most engineers will choose and have chosen redis or memcached over the alternatives. The GIL is still a huge factor in these decisions.
Yes, if you are going to be doing caching in python, you are almost certainly going to be caching it in a separate service and serializing across process boundaries. If you are going to be holding onto a connection pool as well (PG bouncer being the most typical). More generally, any sort of shared resource that would require or benefit strongly from shared memory model needs to be pushed into a sidecar service written in a language that actually supports efficient shared memory model. These are precisely the sorts of problems that the GIL causes. There are standard ways to work around it and most python developers can reach for these solutions, but this is not a contradiction to the fact that the GIL has limited your choice in the matter.
If he was just saying that, he’d probably be downvoted for being true but irrelevant and not meaningfully contributing.
But he’s actually saying that plus “therefore, Python is bad (implying that Python can’t use shared memory between processes).” Which would be a productive, relevant contribution except for the fact that it’s not true.
> More generally, any sort of shared resource that would require or benefit strongly from shared memory model needs to be pushed into a sidecar service written in a language that actually supports efficient shared memory model.
That’s I guess technically true, if you included the stdlib modules which directly support this and are themselves written in (I assume) C. But, “you might have to use the standard library” is…not much of an impediment.
That is why typically python webservers run in multiprocess mode but Java (for example) webservers typically runs in threaded mode.
My point was just that the GIL, while not a dealbreaker or anything, actually _does_ affect how a program is written. So it's implicitly noticeable in my day-to-day.
The python ways work fine, so it's OK even with GIL, but there are other ways as well.
Is this actually showing that it's less efficient though? People rarely complain about Erlang doing the same thing. "You have to spin up a proper task queue rather than firing off an unmanaged background thread" does not sound like an unambiguous negative to me.
If you want to share low level memory between process, use SharedMemory: https://docs.python.org/3/library/multiprocessing.shared_mem...
If you want to share high level data structure between process, use diskcache: http://www.grantjenks.com/docs/diskcache/tutorial.html
This is, granted, not as straightforward as just sharing a variable between threads, but it will get you far.
What I'm getting at is that JS had the exact same problem, and it offers the same ability for sharing blocks of raw memory. But the same pitfalls for any actual structured object.
Instead, we have to serialize/unserialize (creating a copy) from a separate worker, process, or disk source, it's performance is shite for objects of large size.
Message passing is not ideal for large pieces of data. Shared memory is hundreds of times faster.
That's why diskscache is better as an alternative for complex objects: https://pypi.org/project/diskcache/
It's not as good as a simple shared variable, but it's surprisingly performant, since it uses memory-mapped files.
Funny thing here is that PHP works exactly the same with its share nothing architecture. You always need to go outside of PHP handle state between requests.
When I started doing PHP years ago this was one of the first things I stumbled upon on, used to being able to easily share state in a backend. Juniors or non-programmers does usually not think about this at all and thus is not limited by it, whereas programmers with experience from another language, but without any deep PHP knowledge, will always trip up on this, finding it awkward and annoying (like I did).
And yes, the share nothing architecture will change how you write programs. Now many years later I'm used to this and don't see it as problem anymore (almost the opposite).
But if you also need to follow the share nothing architecture on Python, what benefits does it give vs PHP? Is it the community only? Because Python is generally slower than PHP.
I don't consider myself as a Python developer, but based on my knowledge I have hard time finding compelling arguments for picking Python as (web) backend. I rather pick PHP (I have bias), Golang or Java. Nodejs vs Python it a tough one, perhaps nodejs because I can write in TypeScript, but nodejs is not a technology I like.
A programming language with better ergonomics, developer experience and more mature community.
Better developer experience for Python is probably true, more mature community I can't say either way.
Edit: One thing that would be nice in PHP is decorators.
15 years I used to say "I wish PHP had feature X just like in language Y". But there's a moment where it's better not to wait and just to use language Y.
meaning, if the GIL were removed from Python, the performance of threaded concurrency would soar, asyncio would not move an inch.
the project is generally open to PR to remove it as long as the performance doesn't suffer.
and i'll be honest: if you're writing code thats so performance critical that you're worrying about the GIL... why the hell do you use python in the first place? use at least a compiled language.
If lacking a GIL actually incurred a 40% performance penalty in general and not as a consequence of design decisions in Python's internals, we'd expect to see the fastest languages all sporting GILs, and that is really not the case.
Certainly python could have instead been a compiled language but then it’d be fundamentally different language. Are you implying that all of Pythons features could be preserved without a GIL and no performance loss if say a full rewrite was possible?
But if we're willing to accept some changes to the C API, it's at least possible to make the GIL less global.
It really should be obvious that it's possible to have multiple Python interpreters in the same process, where multiple independent threads run Python code in parallel, with occasional calls into a shared data structure implemented as a multi-threaded C extension module.
Currently the GIL makes this impossible: you either can have the multi-threaded C extension module in a single process (but then the Python threads will be limited by Amdahl's law unless you spend >99.9% of CPU time inside the extension module), or you can use multiprocessing which lets the Python code run in parallel, but than the C extension module will have to figure out how to use shared memory.
This is a massive, massive problem for us. We're already invested almost a year of developer time into changing C++ libraries to tell all those pesky std::strings to allocate their data in a shared memory segment. Even then, we've only managed this for some of our shared data structured so far, so this only allows us to parallelize around half of our Python stuff. So in effect, the GIL is causing massive extra complexity for us, and still prevents us from using more than ~2 CPU cores.
We would have been massively better off if 15 years ago we picked Javascript instead of Python. JS is also "single-threaded" like Python, but the JS interpreter lock is much less of a problem because it's not global.
Now Python currently has a "sub-interpreter" effort underway that refactors the interpreter to avoid all that global state and make it per-interpreter. But I somehow doubt that this approach to remove the GIL will be accepted, because again, it will slow down single-threaded execution: e.g. obtaining the `PyObject*` of `None` is currently simply taking the adress of the `_Py_None` global variable. Python will need to split this into one `None` object per interpreter, because (like any Python object) None has a reference count that is mutated all the time. But existing extension modules are accessing the `Py_None` macro -- they don't provide any context which interpreter's `None` they want! This can be solved with some TLS lookups ("what interpreter is the current thread working with"), but I suspect that will be enough of a slowdown that the whole approach will be rejected (since "no performance loss for single-threaded code" seems to be a requirement).
I think Python will get rid of the GIL eventually, but it will take a Python 4.0 with a bunch of breaking changes for C extensions to do so without significant performance loss.
Fair enough, but sometimes your freedom of choice may be limited. We have a large push for Python at our org, and for most people that's probably fine (or even really good), but I'm holding out as long as I can with Matlab and Julia.
Python has now passed Java in TIOBE, which means it has a HUGE number of people using it. That represents a tremendous amount of collective investment and work in that ecosystem.
C/C++ obviously provides nigh-unbounded access to the hardware for doing "serious stuff" like databases, high performance IO/big data/etc.
Java has pretty-darn-good abilities to do "serious stuff" with its threading models and optimizing JVM.
But Python is basically capped by the GIL. So while the amount of code written in Python (and Javascript I'd argue) is massive... does any of it substantively push forward the state of the art? Will layers of the OS improve? Will new databases or cache layers or large scale data processing be improved/advanced?
We're basically at the end of Ghz scaling, it's all increasing wafer sizes and transistor counts ... lots of processors. LOTS of processors.
If the #2 software language in TIOBE can't fundamentally properly use the hardware that the next decade will be running on outside of a core or two... that's a problem.
All our devices have been sidestepping this at the consumer level with two or four cores for the last decade, while server counts have been expanding.
Four cores can ignored at the application level because other cores can do OS maintenance tasks, UI rendering tasks, etc etc etc.
But if your 2025 consumer device has 12-32 cores, and your software can only run on one of them... and it's the #2 programming language, and the reason is the GIL and it's baked so deeply and perniciously into your entire software ecosystem...
Then to your point, why the hell will people use python? And then it will tumble to irrelevance.
But I want even more parallelism, even computing say 20 plots with seaborn.. I'd like it to be parallel and use all my cores, not hang around at 150% cpu usage
What I consider a bigger issue is the way JITs are still not embraced by CPython, but that is a talk for another day.
If a serverless function needs 1 second of the actual CPU work (i.e. real computation, not CRUD or feeding the GPU), wouldn't it be nice to cut user-visible latency to 250-300 milliseconds?
"Serverless" is about processes, while this article is about threads. Different levels.
The GIL has brought me great strife and suffering. If you do anything remotely performance then Python is pain. Also, Python performance is so cataclysmically bad that when you use Python it has a nasty habit of becoming needlessly performance critical.
edit: I have ranted more than usual about python slowness in the last few weeks. The fact is that python is an otherwise great language, powerful, expressive but with a gentle learning curve and a great ecosystem, but the slowness of its primary implementation really drags it down (and because of the ecosystem it is hard to switch to a different implementation).
I wish I could get a different tool. Unfortunately machine learning and data science live and breath Python. It’s an absolute disaster and there is no meaningful alternative.
Jupyter Notebooks can also die in a fire. Go ahead and call Python glue and say to use a different tool if you want.
Unfortunately Python is a black hole or inertia. The one and only good thing about Python is some really great libraries are written in Python. This has resulted in an environment where Python sucks but the cost to move to a language that doesn’t suck is astronomical.
Maybe I am complaining I can’t drill a hole with a knife. Call me in 20 years when drills have been invented and knife lobby has been abolished.