[HN Gopher] What's up, Python? The GIL removed, a new compiler, ... ___________________________________________________________________ What's up, Python? The GIL removed, a new compiler, optparse deprecated Author : BiteCode_dev Score : 94 points Date : 2023-07-30 19:32 UTC (3 hours ago) (HTM) web link (www.bitecode.dev) (TXT) w3m dump (www.bitecode.dev) | mkoubaa wrote: | And alternative C APIs are being proposed, which is as exciting | as all of the above | fbdab103 wrote: | Still not encouraged by the no-GIL, "We don't want another Python | 2->3 situation", yet very little proffered on how to avoid that | scenario. More documentation on writing thread-safe code, | suggested tooling to lint for race conditions (for whatever it is | worth), discussions with popular C libraries, dedicated support | channels for top tier packages, what about the enormous long-tail | of abandoned extensions which still work today, etc. | doctoboggan wrote: | The big and obvious difference is that all the GIL vs no-GIL | stuff happens in the background and your average python dev can | just ignore it if they want to. The interpreter will note if | you have C extensions that don't opt in to no-GIL and then will | give you the GIL version. | | This is _very_ different to the 2-to-3 transition where | absolutely every single person, even those who couldn't care | less, had to change their code if they wanted to use python 3. | threatripper wrote: | I was assuming that no-GIL will only be enabled if all imported | libraries support it. That means that they are marked as no-GIL | ready and otherwise the import would throw an exception. Not | sure how it is implemented now but that sounded very reasonable | to me. The no-GIL compatible code would start with the core | libraries and then expand from that. Using legacy libraries | just means that you have to revert back to GIL-mode. Any no-GIL | enabled library should 100% still function in GIL-mode, so I | don't expect the Python 2->3 transition situation to repeat. | LexiMax wrote: | In a past life I hacked on PHP for a living, and in the time it | took Python 2 to ride off into the sunset, PHP got two major | migrations under its belt in 5.2 to 5.3, and then again 5.6 to | 7.0. | | It was amazing to see the contrast between the two languages. | PHP gave you plenty of reasons to upgrade, and the amount of | incompatible breaking changes was kept to a minimum, often | paired with a way to easily shim older code to continue | working. | | I really hope to see no-GIL make it into Python, but in the | back of my mind I also worry about what lessons were learned | from the 2 to 3 transition. Does the Python team have a more | effective plan this time around? | charrondev wrote: | I've taken an application codebase from PHP 5.3 to 8.2 now | and it was relatively easy the whole way. | | The real key to minimize the pain was writing effective | integration tests with high coverage. We didn't have a good | test suite to start but once we added some utilities to | easily call our various endpoints (and internal API client if | you will) and make assertions about the coverage came | quickly. | | Popular frameworks like Laravel offer such test utilities out | of the box now. | | That combined with static analysis tools like psalm make it | so we can fearlessly move past major upgrades. | | One thing I was surprised at was just how much crap PHP | allowed with just a notice (not even a warning for a long | time). A lot of that stuff still works (although over time | some notices have progressed to warnings or errors | gradually). We have our test suite convert any notices or | warnings to exceptions and fail the test case. | cvnmalk wrote: | Which, except for optparse, was all on the front page yesterday. | So optparse is deprecated. More work I guess apart from auditing | extensions for threading. | | Life is great in the Python treadmill. | devwastaken wrote: | This is exactly what I have been looking forward to. Allow me to | do no-gil, let me the developer make that choice. There are | issues with that certainly, but I am conscious of this fact and | given an analysis of no-gil benefits it is significantly more | beneficial to have no-gil for certain use cases. | | One of the most significant of these cases to me is threading | outside an Operating system context. What if I want to use both | of the cores to a Cortex M0? Multiprocessing can't help me, there | are no processes. If I need locking, I will impliment it using | the platform I have available to me. | | The second is the fact that CPU's are increasingly scaling in | core count. When I have to use multiprocessing the program | becomes far more complex than one would expect. Why am I doing | message passing and shared memory when the OS and CPU supplies | better tools already? It also pollutes the process ID's. Imagine | if we built every application in Python - there would be hundreds | of thousands of individual processes all to use multiple cores. | Because this is a problem mostly unique to python we often end up | having to build applications in other languages that otherwise | would have been better in Python. | | I want a world where I can say "just use python" to almost | anything. Telling new coders to drop their favorite language and | use any other language to get the result they want immedietely | kills the innovation they are working on. Instead of spending | time creating the idea, they're spending time learning a | languages I believe are unnecessary. | andrewstuart wrote: | From reading the thread on HN the other day, it sounds like | removing the GIL isn't really of much value. Maybe for somewhat | obscure multithreading cases. | | Is that right? | Jtsummers wrote: | That discussion was amusing. Removing the GIL opens up the | possibility of actually getting a real performance benefit from | multithreaded Python code. That's the value. Given every modern | desktop and server is multicore (and increasingly getting to | tens of cores if not hundreds), multithreading in Python | unhampered by the GIL will be a useful thing. And no, | multiprocessing is not a good alternative to multithreading. | It's just an alternative, but it's slower, uses more memory, | and coordination between processes is slower than between | threads. | oivey wrote: | That was the opinion of a handful of vocal posters. The | overhead of using multiprocessing and/or some network service | is extremely high for a lot of applications. | FartyMcFarter wrote: | I would disagree with that. | | The GIL means you can't use Python multithreading in order to | take advantage of more CPU time by parallelism. Obviously | getting rid of the GIL makes that a real option, just as it is | in other languages. | squeaky-clean wrote: | Currently, yes that's kind of true. But it's really only | considered obscure because the GIL makes it so you either have | to do some weird non thread pattern or go with a different | language, and people often go with a different language. | | Kind of a Catch-22 of "Well no one uses it that way, so why | should we make it possible to use it that way? Well, no one | uses it that way because it's impossible to use it that way" | kukkamario wrote: | Well Python doesn't really do proper multi-threading currently | thanks to GIL blocking any additional execution threads. So | removing it would enable making Python code that is actually | multi-threaded without resorting to extra processes and their | overhead. | | So if you are writing small single process Python script then | removing GIL shouldn't really change much. If you are doing | some heavier computing or eg. running server back-end, then | there are significant performance gains available with this | change. | umanwizard wrote: | You don't have to use separate processes to get the benefit | of multithreading in Python today -- you can also call into a | library written in native code that drops the GIL (e.g. Numpy | or Pytorch). | cpgxiii wrote: | That only works in some cases, if the boundary between | Python and native code is absolute. In many cases users | want to extend/configure the behavior of that native code, | e.g. through callbacks or subclassing, and the GIL makes | the behavior prohibitively slow (needing to lock/unlock to | serialize at any of these potential Python<->native | boundaries) or unsafe (deadlocks/corruption if the GIL | isn't handled). | | There's a lot of C++ code bound in python (e.g. via | pybind11) where the GIL currently imposes a hard bound on | how users can employ parallelism, even in "nominally" | native code. | masklinn wrote: | Even then the GIL can cause issues, concerns of PyTorch are | specifically one of the motivations of the PEP, and one of | the reasons Meta / FB really really wants this: | | > In PyTorch, Python is commonly used to orchestrate ~8 | GPUs and ~64 CPU threads, growing to 4k GPUs and 32k CPU | threads for big models. While the heavy lifting is done | outside of Python, the speed of GPUs makes even just the | orchestration in Python not scalable. We often end up with | 72 processes in place of one because of the GIL. Logging, | debugging, and performance tuning are orders-of-magnitude | more difficult in this regime, continuously causing lower | developer productivity. | umanwizard wrote: | I feel like orchestrating thousands of GPUs is such a | niche use case that it's fair to expect the people | wanting to do it to learn a more suited language, rather | than ruining Python for everyone else. | sidlls wrote: | It's (likely) much less expensive (in many ways, not just | financially) to employ a larger number of python | programmers than a smaller number of them skilled in a | language more appropriate for the use case. Engineer | flexibility, salary costs, maintenance/correctness | concerns with implications for development time, etc., | are all factors here. The technical choice of "python or | not python" is rarely the only--or even most important-- | choice to make. | csmpltn wrote: | There are plenty of other Python VMs that don't have a GIL and | can be used already today, out of the box (examples include | Jython and IronPython). Despite that fact - CPython remains the | most popular Python VM out there (it utilizes a GIL). | | Instead of waiting for the GIL to be removed out of CPython - | take your fancy Python code and just run it using a different | VM. It's literally as simple as that. | | If the GIL was such a bottleneck as people make it out to be - | people would move off of CPython a long time ago. But they | won't, despite having the options. This only serves to prove | that 95%+ of the workflows people build with Python can be | satisfied regardless of GIL, often using some of the other | parallelism mechanisms available in Python today | (multiprocessing, asyncio, etc). | | Most of the stuff people build with Python are CRUD apps, | Jupyter notebooks, automations, tinkering, small hacks, etc. If | you're okay with not utilizing all of your 64k CPUs at home - | Python's multiprocessing and asyncio libraries should serve you | just fine. | | The whole GIL/No-GIL conversation is a complete waste of time | and a distraction. People have all the options they need | already here and now - but slinging crap at eachother over an | issue tracker is so much fun that people can't help it. | oivey wrote: | People stay on CPython due to the performance of C extensions | and the vast ecosystem based on them. The fact that people | have stuck with CPython isn't at all evidence that they like | the GIL or that it doesn't lead to significant technical | problems. | | Besides the C extension issue, Jython is based on Python 2.7 | and IronPython appears to be on 3.4. These aren't serious | alternatives. | quickthrower2 wrote: | Would a large codebase seemlessly run on another interpreter? | bafe wrote: | Not likely, particularly if you depend on modules written | (partly) in C like numpy/scipy etc | quickthrower2 wrote: | I just did some searching around PyPy and that seems to | be the case. IronPython is out of support now but the | looks of it. Which is a shame. I heard of it 10 years | ago, but assumed it was some "Microsoftized Python" and | not at all a compatible thing :-) | actionfromafar wrote: | If you have a lot of code, there's plenty of Internet drama | to be had in moving to another runtime, too. | masklinn wrote: | > Maybe for somewhat obscure multithreading cases. | | They're only "somewhat obscure" because currently you can't do | it at all, so you don't do it and you do something else: it's | of value for any case where you're multithreading for | computational parallelism (as opposed to IO concurrency). The | PEP also outlines a bunch of other situations where using | process-based parallelism is problematic: | https://peps.python.org/pep-0703/#motivation | | With the proviso that while it will work for all pure-python | code out of the box[0] loading any _native_ package which has | not opted into "no gil" mode will re-enable the GIL: | https://peps.python.org/pep-0703/#py-mod-gil-slot | | [0] modulo new race conditions where the code relied on the GIL | for correctness, something which isn't _strictly_ correct and | can already break when the scheduler logic changes | [deleted] | Spivak wrote: | Right now multi-threading makes your Python code (that isn't | really C) slower. The only real use of it is time slicing so | you don't starve more important code like the web server or UI | thread. You still have all the concurrency issues because your | threads can still still be paused and resumed at arbitrary | times. It does allow some operations in Python to be atomic but | I, maybe naively, assume that those cases will be guarded by | new, not whole interpreter, locks. | | With no-gil your multithreading code can, with no change to | your code, take advantage of multiple cores and actually speed | up your program. If | wmwmwm wrote: | Historically I've written several services that load up some big | datastructure (10s or 100s of GB), then expose an HTTP API on top | of it. Every time I've done a quick implementation in Python of a | service that then became popular (within a firm, so 100s or 1000s | of clients) I've often ended up having to rewrite in Java so I | can throw more threads at servicing the requests (often CPU | heavy). I may have missed something but I couldn't figure out how | to get the multi-threaded performance out of Python but of course | no-GIL looks interesting for this! | wood_spirit wrote: | That's right. | | In the past, for read-only data, I've used a disk file and | relied on the the OS page cache to keep it performant. | | For read-write, using a raw file safely gets risky quickly. And | alternative languages with parallelism runs rings around | python. | | So getting rid of the GIL and allowing parallelism will be a | big boon. | Waterluvian wrote: | No, that's about right. | | The response, which isn't technically wrong, is "unless you're | CPU bound, your application should be parallized with a WSGI. | You shouldn't be loading all that up in memory so it shouldn't | matter that you run 5 Python processes that each handle many | many concurrent I/O bound requests." | | And this is kinda true... I've done it a lot. But it's very | inflexible. I hate programming architectures/patterns/whatnot | where the answer is "no you're doing it wrong. You shouldn't be | needing gigs of memory for your web server. Go learn task | queues or whatever." They're not always wrong, but very | regularly it's the wrong time to worry about such "anti | patterns." | rrishi wrote: | I am not too deeply experienced with Python so forgive my | ignorance. | | But I am curious to understand why you were not able to utilize | the concurrency tools provided in Python. | | A quick google search gave me these relevant resources | | 1. An intro to threading in Python | (https://realpython.com/intro-to-python- | threading/#conclusion...) | | 2. Speed Up Your Python Program With Concurrency | (https://realpython.com/python-concurrency/) | | 3. Async IO in Python: A Complete Walkthrough | (https://realpython.com/async-io-python/) | | Forgive me for my naivety. This topic has been bothering me for | quite a while. | | Several people complain about the lack of threading in Python | but I run into plenty of blogs and books on concurrency in | Python. | | Clearly there is a lack in my understanding of things. | Jtsummers wrote: | Re (3): asyncio does not give you a boost for CPU bound | tasks. It's a single-threaded, cooperative multi-tasking | system that can (if you're IO bound) give you a performance | boost. | aardvark179 wrote: | Threading in Python is fine if your threads are io bound or | spend their time in a C extension which releases the GIL, if | you are bound then the GIL means effectively one thread can | run at a time and you gain no advantage from multiple | threads. | teraflop wrote: | The whole point of the GIL is that even if you use Python's | threading or asyncio, you don't get any benefits from scaling | beyond a single CPU core, because all of your threads (or | coroutines) are competing for a single lock. They run | "concurrently", but not actually in parallel. The pages you | linked explain this in more detail. | | In theory, multiprocessing could allow you to distribute the | workload, but in a situation like OP describes -- just | serving API requests based on a data structure -- the | overhead of dispatching requests would likely be bigger than | the cost of just handling the request in the first place. And | your main server process is still a bottleneck for actually | parsing the incoming requests and sending responses. So | you're unlikely to see a significant benefit. | [deleted] | wmwmwm wrote: | You can throw python threads at it, but if each request | traverses the big old datastructure using python code and | serialises a result then you're stuck with only one live | thread at a time (due to the GIL). In Java it's so much | easier especially if the datastructure is read only or is | updated periodically in an atomic fashion. Every attempt to | do something like this in python has led me to having to | abandon nice pythonic datastructures, fiddle around with | shared memory binary formats, before sighing and reaching for | java! Especially annoying if the service makes use of handy | libraries like numpy/pandas/scipy etc! | threatripper wrote: | You have a single big data structure that can't be shared | easily between multiple processes. Can't you use | multiprocessing with that? Maybe mapping the data structure to | a file and mmapping that in multiple processes? Maybe wrapping | the whole thing in database instead of just using one huge | nested dictionary? To me multi-threading sounds so much less | painful than all the alternatives that I could imagine. Just | adding multi-threading could give you >10x improvement on | current hardware without much extra work if your data structure | plays nice. | kroolik wrote: | One annoying part with multiprocessing in Python is that you | could abuse the COW mechanism to save on loading time when | forking. But Python stores ref counters together with objects | so every single read will bust your COW cache. | | Now, you wanted it simple, but got to fight with the memory | model of a language that wasn't designed with performance in | mind, for programs whose focus wasn't performance. | dathinab wrote: | > You have a single big data structure that can't be shared | easily between multiple processes. Can't you use | multiprocessing with that? Maybe mapping the data structure | to a file and mmapping that in multiple processes? Maybe | wrapping the whole thing in database instead of just using | one huge nested dictionary? | | ton of additional complexity, not worth it for many use-cases | and anything on the line of "using multiple processes or | threads to increase python performance" does have (or at | least did have) quite a bunch of additional foot guns in | python | | In that context porting a very trivial ad-hoc application to | Java (or C# or Rust, depending on what knowhow exist in the | Team) would faster or at least not much slower to do. But it | would be reliable estimable by reducing the chance for any | unexpected issues, like less perf then expected. | | Basically the moment "use mmap" or "use multi-processing" is | a reasonable recommendation for something ad-hocish there is | something rally wrong with the tools you use IMHO. | threatripper wrote: | The use case I'm thinking about is very simple: One big | data structure that is mostly read from and sometimes | written to. Use a single mutex with a shared lock for | reading and an exclusive lock for writing. Then the readers | are safe and would only block during updates when one | writer is active. Everything else beside the data structure | can be per-thread and wouldn't interfere. | | The problem why we wouldn't want to port this application | to another language is 100k lines of existing code that is | best written in Python and no resources to rewrite all | that. | ggm wrote: | > _Basically the moment "use mmap" or "use multi- | processing" is a reasonable recommendation for something | ad-hocish there is something rally wrong with the tools you | use IMHO._ | | Hmm. So you're saying only languages which bury lock and | mutex over shared data are appropriate to use for async | parallelism over shared data? Because calling explicit | lock() and releae() isn't that hard. However it does incur | a function call overhead. I suppose some explicit in | language support could minimise that partially. | strictfp wrote: | My tip for this is Node.js and some stream processing lib like | Highland. You can get _ridiculous_ IO parallelism with a very | little code and a nice API. | | Python just scales terribly, no matter if you use multi-process | or not. Java can get pretty good perf, but you'll need some | libs or quite a bit of code to get nonblocking IO sending | working well, or you're going to eat huge amounts of resources | for moderate returns. | | Node really excels at this use case. You can saturate the lines | pretty easily. | xcv123 wrote: | > I may have missed something | | You did not miss anything. The GIL prevents parallel multi | threading. | jeremycarter wrote: | Similar experience. Even with multi process and threads python | is slow, very slow. Java, Go and .NET all provide a very | performant out of box experience. | brightball wrote: | This is actually one of the reasons I was drawn to Ruby over | Python. Ruby also has the GIL but jRuby is an excellent option | when needed. | antod wrote: | I wonder what lead to JRuby attracting support while Jython | not? I know the Jython creator went on to other things (was | it eg IronPython for dotnet?). I suppose it was the inverse | with dotnet - eg IronPython surviving while IronRuby seems | dead. | | Is it just down to corporate sponsorship? | nwallin wrote: | > I may have missed something but I couldn't figure out how to | get the multi-threaded performance out of Python | | Multiprocessing. The answer is to use the python | multiprocessing module, or to spin up multiple processes behind | wsgi or whatever. | | > Historically I've written several services that load up some | big datastructure (10s or 100s of GB), then expose an HTTP API | on top of it. | | Use the python multiprocessing module. If you've already | written it with the multithreading module, it is a drop in | replacement. Your data structure will live in shared memory and | can be accessed by all processes concurrently without incurring | the wrath of the GIL. | | Obviously this does not fix the issue of Python just being | super slow in general. It just lets you max out all your CPU | cores instead of having just one core at 100% all the time. | godelski wrote: | This exists, but one of two things happen, which still | significantly slows things down. Either 1) you generate | multiple python instances or 2) you push the code to a | different language. Both are cumbersome and have significant | effects. The latter is more common in computational libraries | like numpy or pytorch, but in this respect it is more akin to | python being a wrapper for C/C++/Cuda. Your performance is | directly related to the percentage of time your code spends | within those computation blocks otherwise you get hammered by | IO operations. | hanniabu wrote: | Will writing multithreaded code become easier? Or will the | developer UX remain the same? | dpedu wrote: | The opposite, writing multithreaded code will get harder | because you'll likely need to handle concurrency issues | yourself that the GIL previously avoided. But, the tradeoff is | that multithreaded programs could now actually achieve | multithreaded performance gains. | bvrmn wrote: | A single Go thread still replaces 10 Python threads, speaking | very roughly. It's a quite particular narrow set of problems | noGIL would solve. | Jtsummers wrote: | > writing multithreaded code will get harder because you'll | likely need to handle concurrency issues yourself | | I'd phrase this differently: Writing _correct_ multithreaded | code will be just as challenging (or not, depending on the | person and their comfort with concurrent and parallel code | development) as before, but now you won 't be able to get | away with _sloppy_ multithreaded code that relied on the GIL | to not break. | fbdab103 wrote: | It was correctly written to the invariant promises of the | platform at the time. If Python is altering the deal, that | does not suddenly make the library writer at fault. | oivey wrote: | There seems to be some confusion here. The GIL is not an | invariant of Python that makes your code thread safe. | Python is not altering the deal. You can still use | threads to write concurrent code in Python today, and | you'll still run into all of the classic concurrency | related bugs. | | People just mostly don't bother writing threaded code in | Python today because it provides no performance benefit. | That may change, and it very likely will expose many | threading bugs that already exist in many libraries that | just have never been found. | BiteCode_dev wrote: | Summary: | | - Python without the GIL, for good | | - LPython: a new Python Compiler | | - Pydantic 2 is getting usable | | - PEP 387 defines "Soft Deprecation", getopt and optparse soft | deprecated | | - Cython 3.0 released with better pure Python support | | - PEP 722 - Dependency specification for single-file scripts | | - Python VSCode support gets faster | | - Paint in the terminal | bigbillheck wrote: | Python's been a little too happy to hard-deprecate things for my | liking, so this soft-deprecation sounds pretty good. | schemescape wrote: | The title says "GIL removed", but the article says "This means in | the coming years, Python will have its GIL removed." | | I'm assuming the article is correct and the GIL has not been | removed yet (but there is a plan to remove it in the future). If | that's not the case, please correct me! | Jtsummers wrote: | It's not been removed. PEP 703 has been accepted and they've | got a path forward to no-GIL. No-GIL versions will be available | as experimental versions starting with 3.13 or 3.14. | | https://peps.python.org/pep-0703/ | | https://discuss.python.org/t/a-steering-council-notice-about... ___________________________________________________________________ (page generated 2023-07-30 23:00 UTC)