I wrote a program in Python to read some huge Json files. It took forever to finish. Turned out I could optimize it with some simple changes, which reduced 10 minutes to 10 seconds (not literally, just figurative) and made a difference in huge files only. Later I rewrote the program in Rust. And you know what happened? It was slower than the Python version. Only after understanding what I was doing and making right changes made the Rust version faster.
Most of the time its the design of the code or libraries that slows down. The language might play a huge role in performance, but it depends on what type of code and application it is.
I actually wanted write a blog post about this… if I still have the project data I might explain what happened. BTW this had nothing to do with Ai.
As an OPS guy you know what really grinds my gears? Developers not paying attention to shit like this.
We have a job in production that is a powershell script calling a powershell script calling a java applet. Now you may already be thinking “what is this abomination?” And you’re right, but that java application is set to DEBUG. IN PRODUCTION. So every time it runs it generates 1gb of logs.
Do they fix it? No of course not because if it’s not broken don’t fix it. But Jesus Christ we have people developing without understanding fundamentals like “YOU DONT LEAVE DEBUG ON IN PRODUCTION”.
Counterpoint, I wrote a Python program that reads a load of JSON and runs regex searches over it. It was quite slow. Rewrote it in Rust as a straight 1:1 port, no algorithmic changes. 50x speedup.
I think you must have either done something very wrong or your Python program didn’t really do anything other than call Python built-ins that are actually written in C.
Did you use a profiler to find the bottlenecks? Did you try using cjson to speed up the json parsing? I would also avoid using the stdlib regex library too. It’s probably more of a convenience/reference implementation, not something to be intended for high performance. Maybe there’s a re2 wrapper for Python or a similar regex library in C with Python bindings.
Rewriting in Rust is fine, but good Python devs know how to find bottlenecks in their software and replace them with fast implementations. I’ve written plenty of performant Python code, it’s not very hard to profile and optimize. Usually the performant stuff is already written in C/C++ or Fortran anyway (numpy, PyQt, etc.)
No. It was a simple enough program that there were no areas for improvement anyway. I also did not use a profiler for the Rust code.
good Python devs know how to find bottlenecks in their software and replace them with fast implementations
In my experience this is also a sweet sounding lie to make people feel ok with using Python. Yes in some case you make a big mistake and there’s a large bottleneck you can easily remove… Or your program has a nice small hotspot where it spends most of its time and you can just write that bit in C++ (AI is the obvious example).
But most programs are not like that. They’re more like MS Word. Slowness is evenly distributed through the code. There is no hotspot to remove.
As an example of this, look at Nicholas Nethercote’s excellent series of blogs on making the Rust compiler faster: https://nnethercote.github.io/
The “bottlenecks” they find result in 1% speedups.
If you didn’t use a profiler, then how can you be sure that the issue was Python and not something else? If the slowness really is evenly distributed through the code as you suggest, then a profiler would show that almost instantly and it’s very easy to do that in Python using cProfile.
On top of that, the Python standard library is built for convenience, not performance. The nature of it being a standard library means that the implementation has to be simple. fastregex uses LLVM and SIMD for example, that’s something that’s wildly impractical for the Python stdlib to support. In contrast, I have no idea what regex or JSON library you used for your Rust code, but if it were outside the stdlib, chances are high that it had much more leeway to optimize performance because it didn’t have all the other maintenance obligations that stdlib code needs to support.
All of this is just pure speculation on my part, but ultimately I’m trying to make a point that it is hard to say that the difference was caused by a language issue and not something else. There are lots of other things that could be contributing to this difference and you can’t really say for sure without meaningful diagnostics.
As an example of this, look at Nicholas Nethercote’s excellent series of blogs on making the Rust compiler faster: https://nnethercote.github.io/
The “bottlenecks” they find result in 1% speedups.
The kinds of software that you and I write on a daily basis is nothing compared to pieces of software that get millions of man-hours per year. Assuming you’re not Linus Torvalds or Ted Ts’o hiding behind a funny alias, of course. I don’t think anyone is suggesting that it’s a good idea to write a compiler in Python (outside of prototyping purposes perhaps) since it’s obviously not I/O bound, but if you and I are trying to optimize something we wrote ourselves, we’re more likely to be in the “nice small hotspot” domain you described, rather than the 1% bottleneck speedups discussed in the link you posted.
Very cool link though by the way, I look forward to reading as much of it as I can…
If you didn’t use a profiler, then how can you be sure that the issue was Python and not something else?
It was a relatively simple program and I am good at programming.
The point is, I put the same amount of effort into writing the same program in Python and Rust, and Rust was 50x faster. With AI, I don’t see any reason to use Python these days anyway. I never bought the productivity arguments before (Rust is easily as productive as Python), but with AI Rust is definitely more productive than Python because of the much stronger static checks.
It wasn’t a very wrong what I did in Python. I did the obvious thing. While I do not remember details, I remember it had something to do with adding items I think. But sadly I have not documented this issue, that’s on me. It was only noticeable for really huge files like 50MBytes json. Edit: Most weren’t this big, but it also combined over 100 Json files into one, so a search would search them all through and be able to save as a single file.
What about the fact that runtime startup alone auto-disqualifies python for all short-lived process use-cases?
Or the fact that you can’t do concurrency especially across the language barrier from another language without multiple python runtimes orchestrated with a queue and IPC because of possible process-wide global state and similar concerns/assumptions for any python library dependency that is not all native across its own dependency chain?
“languages are just tools” and “use the right tool for the job” were already stupid catch phrases. Pretending languages don’t matter is a big further step into this shallow faux-intellectualism masquerading as wisdom.
What about the fact that runtime startup alone auto-disqualifies python for all short-lived process use-cases?
While Python’s start-up time is a lot slower than a corresponding compiled program, in most cases it’s not slow enough to matter even if the process itself is short-lived:
$ hyperfine 'python3 -c "pass"'
Benchmark 1: python3 -c "pass" (412 runs)
mean ± σ min … max
Wall Time 7.1 ms ± 0.2 ms 6.7 ms … 8.4 ms
Memory 9.4 MiB ± 0.1 MiB 9.1 MiB … 9.5 MiB
If you are running a small program so often that this kind of start-up time matters, then the loop should probably already be implemented in the program itself. In line with the article’s thesis
Yeah nah, Lua runs circles around Python both at runtime and especially at startup. I’ve made me some desktop automation scripts in Lua to call from Alfred, I had to recheck that I didn’t leave static test data in there instead of calling the script, because the results were appearing instantly.
Recently had to develop a Python project, the tests took at least ten seconds to start each single time. This is while I made over a hundred tests for my module and re-ran them after every change.
Recently had to develop a Python project, the tests took at least ten seconds to start each single time. This is while I made over a hundred tests for my module and re-ran them after every change.
Python is dog slow, but if your tests are taking 10 seconds to start (not even run!), then something is catastrophically wrong with your setup. For comparison, for one of my projects, it takes a total of 12 seconds to run nox on a clean slate, which involves setting up venvs for five major versions of Python, installing the package and its dependencies in each, and finally running the 1500 test test-suite five times
It wasn’t my project. Afaict it’s a standard pytest setup with the Litestar framework (unused in my tests) and an in-memory mock Postgre transaction with like five records per test, so choose for yourself which part of this is ‘catastrophically wrong’. However, I can indeed agree that most of it is trash.
Same approach with dozens upon dozens of tests worked snappily as heck in PHP, haven’t yet tried it with my beloved Lua.
It is, yes. But I also commented on Lua vs Python, and if you even try to time them, Lua scripts will be finished before Python starts up. Lua is so fast that people mostly don’t bother making libs for it in C, the fucking interpreter is quick enough for folks to skip any kind of compiling and just write libraries in the interpreted language. Oh, didn’t I mention? The startup thing is with the interpreter, without any kind of bytescript, JIT and such.
In the same vein, the K and Q languages and the KDB+ database by Arthur Whitney are so goddamn fast at array processing that they’re used in banking for decades despite their extremely inscrutable syntax that would shear any Python programmer’s head clean off. They just stay in the cache at most times. And they are also interpreted, not compiled at any time.
Python suffers from the same shit as Java, it has to initialize hundreds of objects before the main program even starts, and then it creates hundreds more. Neither Lua nor JavaScript do that. PHP does to some extent, but the fucker is so fast that it can recreate the entire runtime context on every single request and then drop all of it afterwards, and it’s still quicker than Python.
Oh really? Well guess what, that’s a huge benefit for Lua because its entire total size is around 500 KB. It’s loaded into memory and executed start to finish faster than you blink. If you need a ‘standard library’, just use Penlight. As I already mentioned, vast majority of libraries for Lua are written in… Lua itself, because it’s so goddamn fast. I’m using Fennel, the Lua Lisp that’s transcribed on-the-fly, and it’s still faster than Python. Lua is great for interactive tasks like desktop automation, e.g. with Alfred, Hammerspoon (which latter uses Lua throughout), or for scripting in Termux on the phone where Python would kill the memory immediately.
Lua’s problems with the absence of popular libraries aren’t because of any language issues (even the lack of null can be dealt with), but solely due to its non-adoption in the masses. It is very popular as an embedded language in gaming, though, and that’s not a coincidence, because it fits that niche precisely because of its small size and extraordinary speed.
Well guess what, that’s a huge benefit for Lua because its entire total size is around 500 KB.
Filesize doesn’t matter, if the functionality is missing. Lua is just not a direct comparison and replacement for Python. Penlight isn’t standard library. In example if I want to write a commandline script, I better off doing it in Python. The language is much better to me, has better features, has a standard library builtin and is even installed in all Linux distributions.
Lua is meant to be embedded into other applications, not meant to be used on its own.
Lua’s problems with the absence of popular libraries aren’t because of any language issues (even the lack of null can be dealt with), but solely due to its non-adoption in the masses.
Wrong. This is a design choice, because Lua isn’t meant to be used by its own. The embedded environment is meant to provide the functionality. In example in Neovim they provide their own functionality embedded within the editor. I can’t use that script on a different environment.
Filesize doesn’t matter, if the functionality is missing.
Lua is meant to be embedded into other applications, not meant to be used on its own.
Wrong. Lua is meant to be used on its own, because it’s so freaking good. It provides everything one needs to begin, while allowing for a wide array of libraries to be made. But I know you haven’t made any serious number of scripts in either language, simply because you claim ‘filesize doesn’t matter’, while Lua is so fast partly because of its size.
Wrong. This is a design choice, because Lua isn’t meant to be used by its own.
Wrong again. Lua is amazing on its own, but third-party libraries make it even better.
Or the fact that you can’t do concurrency especially across the language barrier from another language without multiple python runtimes orchestrated with a queue and IPC because of possible process-wide global state and similar concerns/assumptions for any python library dependency that is not all native across its own dependency chain?
This is very out of date. I haven’t written Python for over 4 years and even back then, I was using multiprocessing.Pool for pretty much all parallel processing that I ever needed. Sure, it’s doesn’t fit every use case for concurrency, but for simple stuff it’s perfectly fine.
Not only that, it’s one of the simplest parallel processing APIs I’ve ever used:
from multiprocessing import Pool
deff(x):
return x*x
if __name__ == '__main__':
with Pool(5) as p:
print(p.map(f, [1, 2, 3]))
It’s not outdated, and maybe you didn’t get what I was talking about, but probably because I didn’t word it well. So let me quote someone else instead:
While pure Python code should work unchanged, code written in other languages or using the CPython C API may not. The GIL was implicitly protecting a lot of thread-unsafe C, C++, Cython, Fortran, etc. code - and now it no longer does. Which may lead to all sorts of fun outcomes (crashes, intermittent incorrect behavior, etc.)
This covers the layers below python, but still doesn’t fully cover the process wide restrictions (it’s not just about thread safety, global initialization and resources are very relevant too). It also doesn’t cover the exact same problem which also exists for any layer calling into python from above, which also relies/relied on the GIL for synchronization. This means that you can’t effectively, confidently, and safely scale python without scaling the number of python runtime instances, each in its own full OS process.
The fact that multiprocessing became popular, instead of just scaling/parallelizing with threads, is itself an extension of the GIL/no-GIL circus. But its not the primary point here.
So not only the proposition (which someone referenced in another sub-thread) to move everything into python is in and of itself a self-defeating argument, since it proves a language being a problem (through forcing language lock-in). But even within a language (python), not all problems are solvable still.
Note that this is not all theoretical for me. In one of my previous projects, I had to call into a python library (which didn’t have an adequate alternative) from rust code (through pyo3). And I was forced to scale with multiple python runtimes, each getting one request/message at a time.
And we still didn’t get to any low-level details yet 😉
Ah okay, I see what you’re saying. GIL removal can break FFI code through the C API.
I have a lot of thoughts on this, and most of it is too incoherent to put into a comment someone else can understand, but for the most part, I think the issues are still pretty overblown. I just can’t see a world where Python needs true multithreading support when multiprocessing works just fine for most applications. You find a hot loop, you parallelize it in multiprocessing and just like that, your process runs much faster.
I do think that GIL removal is a terrible idea in general, for the reasons in the quote you provided, but at least it’s optional. I would personally not enable it in anything I maintain for several years if I didn’t have to.
I also think that polyglot code running in the same process is also a bad idea. I can understand calling C or Fortran from Python for numerical processing for example, but doing the reverse (like calling Python from Rust) is something I try to avoid at all costs. In any project I’ve worked on, if significant portions of the codebase were written in different languages, you would just use something like protobuf to specify the I/O protocol between the different languages and call them across a socket. It’s easier to maintain in my opinion since it defines a concrete boundary between the two different portions of code, and also makes it much easier to test each component separately too.
If you didn’t automatically register that requiring spawning full OS processes to scale performance immediately disqualifies a language from a whole plethora of use-cases (which is what the intellectually deficient OP tried to argue against), then I’m not sure you’re qualified to opine on the matter (hint: spawning a thread per task is already too much overhead for many workloads). And I don’t mean any disrespect to you here. Your replies were far from the worst in this thread.
Frankly this thread has been very illuminating. My perception of the average p.d user and their concrete knowledge was very inflated.
And we didn’t even get to low level stuff yet. People are already failing at the macro level. Sad.
If you didn’t automatically register that requiring spawning full OS processes to scale performance immediately disqualifies a language from a whole plethora of use-cases
That’s way too broad of a statement to be true in any absolute sense. It really depends on what you’re doing, and sure, there are plenty of ways to do it stupidly, but a lot of people that are smarter than you and me have thought about ways that the overhead of spawning processes can be mitigated. All I can say is that I’ve had perfectly good success using multiprocessing.Pool and getting near perfect speedups. Is it as fast as threading? No. But it’s good enough. If it’s not good enough for you, then maybe we just have different use-cases, but without talking about concrete examples, we can’t make any specific claims.
And we didn’t even get to low level stuff yet. People are already failing at the macro level. Sad.
What do you want to talk about? Are you writing kernel drivers in Python or something? Why would we talk about writing low level code in Python, that sounds absurdly stupid. Most of the high performance libraries people use are written in Fortran or C. The entire field of data science uses Python, if performance were not a heavily optimized problem, then a lot of people out there must really love wasting their money on compute. Python is a glue language for high performance low level code, everybody knows this already.
Frankly this thread has been very illuminating. My perception of the average p.d user and their concrete knowledge was very inflated.
The thing is also that you can’t separate a language from its ecosystem.
Because it is possible to write the fastest programs in C/C++ and Rust, folks that actually need the fastest performance will use these languages and will go around opening pull requests to fix performance problems in commonly-used libraries.
So, you do often end up with the most performant design anyways, just because the language itself is fast on paper.
I wrote a draft of a service that would take hours to complete. when I optimized it for multithreaded operation instead of taking hours it took around 60 seconds.
write software like you write research papers. first draft > second draft > final draft > publication
I’d love that but it’s difficult when it’s not really my project and anything that is functioning well enough gets you assigned the next ticket at work.
I wrote a program in Python to read some huge Json files. It took forever to finish. Turned out I could optimize it with some simple changes, which reduced 10 minutes to 10 seconds (not literally, just figurative) and made a difference in huge files only. Later I rewrote the program in Rust. And you know what happened? It was slower than the Python version. Only after understanding what I was doing and making right changes made the Rust version faster.
Most of the time its the design of the code or libraries that slows down. The language might play a huge role in performance, but it depends on what type of code and application it is.
I actually wanted write a blog post about this… if I still have the project data I might explain what happened. BTW this had nothing to do with Ai.
As an OPS guy you know what really grinds my gears? Developers not paying attention to shit like this.
We have a job in production that is a powershell script calling a powershell script calling a java applet. Now you may already be thinking “what is this abomination?” And you’re right, but that java application is set to DEBUG. IN PRODUCTION. So every time it runs it generates 1gb of logs.
Do they fix it? No of course not because if it’s not broken don’t fix it. But Jesus Christ we have people developing without understanding fundamentals like “YOU DONT LEAVE DEBUG ON IN PRODUCTION”.
I don’t understand how this is even possible.
I mean, python has a very nice set of tools that run at C speed so it’s not crazy to think you can get good performance out of it.
Counterpoint, I wrote a Python program that reads a load of JSON and runs regex searches over it. It was quite slow. Rewrote it in Rust as a straight 1:1 port, no algorithmic changes. 50x speedup.
I think you must have either done something very wrong or your Python program didn’t really do anything other than call Python built-ins that are actually written in C.
Did you use a profiler to find the bottlenecks? Did you try using cjson to speed up the json parsing? I would also avoid using the stdlib regex library too. It’s probably more of a convenience/reference implementation, not something to be intended for high performance. Maybe there’s a re2 wrapper for Python or a similar regex library in C with Python bindings.
Rewriting in Rust is fine, but good Python devs know how to find bottlenecks in their software and replace them with fast implementations. I’ve written plenty of performant Python code, it’s not very hard to profile and optimize. Usually the performant stuff is already written in C/C++ or Fortran anyway (numpy, PyQt, etc.)
No. It was a simple enough program that there were no areas for improvement anyway. I also did not use a profiler for the Rust code.
In my experience this is also a sweet sounding lie to make people feel ok with using Python. Yes in some case you make a big mistake and there’s a large bottleneck you can easily remove… Or your program has a nice small hotspot where it spends most of its time and you can just write that bit in C++ (AI is the obvious example).
But most programs are not like that. They’re more like MS Word. Slowness is evenly distributed through the code. There is no hotspot to remove.
As an example of this, look at Nicholas Nethercote’s excellent series of blogs on making the Rust compiler faster: https://nnethercote.github.io/
The “bottlenecks” they find result in 1% speedups.
If you didn’t use a profiler, then how can you be sure that the issue was Python and not something else? If the slowness really is evenly distributed through the code as you suggest, then a profiler would show that almost instantly and it’s very easy to do that in Python using cProfile.
On top of that, the Python standard library is built for convenience, not performance. The nature of it being a standard library means that the implementation has to be simple. fastregex uses LLVM and SIMD for example, that’s something that’s wildly impractical for the Python stdlib to support. In contrast, I have no idea what regex or JSON library you used for your Rust code, but if it were outside the stdlib, chances are high that it had much more leeway to optimize performance because it didn’t have all the other maintenance obligations that stdlib code needs to support.
All of this is just pure speculation on my part, but ultimately I’m trying to make a point that it is hard to say that the difference was caused by a language issue and not something else. There are lots of other things that could be contributing to this difference and you can’t really say for sure without meaningful diagnostics.
The kinds of software that you and I write on a daily basis is nothing compared to pieces of software that get millions of man-hours per year. Assuming you’re not Linus Torvalds or Ted Ts’o hiding behind a funny alias, of course. I don’t think anyone is suggesting that it’s a good idea to write a compiler in Python (outside of prototyping purposes perhaps) since it’s obviously not I/O bound, but if you and I are trying to optimize something we wrote ourselves, we’re more likely to be in the “nice small hotspot” domain you described, rather than the 1% bottleneck speedups discussed in the link you posted.
Very cool link though by the way, I look forward to reading as much of it as I can…
It was a relatively simple program and I am good at programming.
The point is, I put the same amount of effort into writing the same program in Python and Rust, and Rust was 50x faster. With AI, I don’t see any reason to use Python these days anyway. I never bought the productivity arguments before (Rust is easily as productive as Python), but with AI Rust is definitely more productive than Python because of the much stronger static checks.
It wasn’t a very wrong what I did in Python. I did the obvious thing. While I do not remember details, I remember it had something to do with adding items I think. But sadly I have not documented this issue, that’s on me. It was only noticeable for really huge files like 50MBytes json. Edit: Most weren’t this big, but it also combined over 100 Json files into one, so a search would search them all through and be able to save as a single file.
yeah, sometimes it feels like the same people complaining about python speed are the ones writing “C” code in python.
What about the fact that runtime startup alone auto-disqualifies python for all short-lived process use-cases?
Or the fact that you can’t do concurrency especially across the language barrier from another language without multiple python runtimes orchestrated with a queue and IPC because of possible process-wide global state and similar concerns/assumptions for any python library dependency that is not all native across its own dependency chain?
“languages are just tools” and “use the right tool for the job” were already stupid catch phrases. Pretending languages don’t matter is a big further step into this shallow faux-intellectualism masquerading as wisdom.
And we didn’t even get to low level stuff yet.
While Python’s start-up time is a lot slower than a corresponding compiled program, in most cases it’s not slow enough to matter even if the process itself is short-lived:
$ hyperfine 'python3 -c "pass"' Benchmark 1: python3 -c "pass" (412 runs) mean ± σ min … max Wall Time 7.1 ms ± 0.2 ms 6.7 ms … 8.4 ms Memory 9.4 MiB ± 0.1 MiB 9.1 MiB … 9.5 MiBIf you are running a small program so often that this kind of start-up time matters, then the loop should probably already be implemented in the program itself. In line with the article’s thesis
Thanks for putting numbers. People really overblow python performance issues when it literally does not matter most times.
Yeah nah, Lua runs circles around Python both at runtime and especially at startup. I’ve made me some desktop automation scripts in Lua to call from Alfred, I had to recheck that I didn’t leave static test data in there instead of calling the script, because the results were appearing instantly.
Recently had to develop a Python project, the tests took at least ten seconds to start each single time. This is while I made over a hundred tests for my module and re-ran them after every change.
Python is dog slow, but if your tests are taking 10 seconds to start (not even run!), then something is catastrophically wrong with your setup. For comparison, for one of my projects, it takes a total of 12 seconds to run nox on a clean slate, which involves setting up venvs for five major versions of Python, installing the package and its dependencies in each, and finally running the 1500 test test-suite five times
It wasn’t my project. Afaict it’s a standard pytest setup with the Litestar framework (unused in my tests) and an in-memory mock Postgre transaction with like five records per test, so choose for yourself which part of this is ‘catastrophically wrong’. However, I can indeed agree that most of it is trash.
Same approach with dozens upon dozens of tests worked snappily as heck in PHP, haven’t yet tried it with my beloved Lua.
Then its the Test environment that is slow, not Python.
It is, yes. But I also commented on Lua vs Python, and if you even try to time them, Lua scripts will be finished before Python starts up. Lua is so fast that people mostly don’t bother making libs for it in C, the fucking interpreter is quick enough for folks to skip any kind of compiling and just write libraries in the interpreted language. Oh, didn’t I mention? The startup thing is with the interpreter, without any kind of bytescript, JIT and such.
In the same vein, the K and Q languages and the KDB+ database by Arthur Whitney are so goddamn fast at array processing that they’re used in banking for decades despite their extremely inscrutable syntax that would shear any Python programmer’s head clean off. They just stay in the cache at most times. And they are also interpreted, not compiled at any time.
Python suffers from the same shit as Java, it has to initialize hundreds of objects before the main program even starts, and then it creates hundreds more. Neither Lua nor JavaScript do that. PHP does to some extent, but the fucker is so fast that it can recreate the entire runtime context on every single request and then drop all of it afterwards, and it’s still quicker than Python.
Lua also doesn’t provide everything Python does and has a totally different use case.
Oh really? Well guess what, that’s a huge benefit for Lua because its entire total size is around 500 KB. It’s loaded into memory and executed start to finish faster than you blink. If you need a ‘standard library’, just use Penlight. As I already mentioned, vast majority of libraries for Lua are written in… Lua itself, because it’s so goddamn fast. I’m using Fennel, the Lua Lisp that’s transcribed on-the-fly, and it’s still faster than Python. Lua is great for interactive tasks like desktop automation, e.g. with Alfred, Hammerspoon (which latter uses Lua throughout), or for scripting in Termux on the phone where Python would kill the memory immediately.
Lua’s problems with the absence of popular libraries aren’t because of any language issues (even the lack of
nullcan be dealt with), but solely due to its non-adoption in the masses. It is very popular as an embedded language in gaming, though, and that’s not a coincidence, because it fits that niche precisely because of its small size and extraordinary speed.Filesize doesn’t matter, if the functionality is missing. Lua is just not a direct comparison and replacement for Python. Penlight isn’t standard library. In example if I want to write a commandline script, I better off doing it in Python. The language is much better to me, has better features, has a standard library builtin and is even installed in all Linux distributions.
Lua is meant to be embedded into other applications, not meant to be used on its own.
Wrong. This is a design choice, because Lua isn’t meant to be used by its own. The embedded environment is meant to provide the functionality. In example in Neovim they provide their own functionality embedded within the editor. I can’t use that script on a different environment.
Wrong. Lua is meant to be used on its own, because it’s so freaking good. It provides everything one needs to begin, while allowing for a wide array of libraries to be made. But I know you haven’t made any serious number of scripts in either language, simply because you claim ‘filesize doesn’t matter’, while Lua is so fast partly because of its size.
Wrong again. Lua is amazing on its own, but third-party libraries make it even better.
This is very out of date. I haven’t written Python for over 4 years and even back then, I was using multiprocessing.Pool for pretty much all parallel processing that I ever needed. Sure, it’s doesn’t fit every use case for concurrency, but for simple stuff it’s perfectly fine.
Not only that, it’s one of the simplest parallel processing APIs I’ve ever used:
from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': with Pool(5) as p: print(p.map(f, [1, 2, 3]))It’s not outdated, and maybe you didn’t get what I was talking about, but probably because I didn’t word it well. So let me quote someone else instead:
This covers the layers below python, but still doesn’t fully cover the process wide restrictions (it’s not just about thread safety, global initialization and resources are very relevant too). It also doesn’t cover the exact same problem which also exists for any layer calling into python from above, which also relies/relied on the GIL for synchronization. This means that you can’t effectively, confidently, and safely scale python without scaling the number of python runtime instances, each in its own full OS process.
The fact that
multiprocessingbecame popular, instead of just scaling/parallelizing with threads, is itself an extension of the GIL/no-GIL circus. But its not the primary point here.So not only the proposition (which someone referenced in another sub-thread) to move everything into python is in and of itself a self-defeating argument, since it proves a language being a problem (through forcing language lock-in). But even within a language (python), not all problems are solvable still.
Note that this is not all theoretical for me. In one of my previous projects, I had to call into a python library (which didn’t have an adequate alternative) from rust code (through pyo3). And I was forced to scale with multiple python runtimes, each getting one request/message at a time.
And we still didn’t get to any low-level details yet 😉
Ah okay, I see what you’re saying. GIL removal can break FFI code through the C API.
I have a lot of thoughts on this, and most of it is too incoherent to put into a comment someone else can understand, but for the most part, I think the issues are still pretty overblown. I just can’t see a world where Python needs true multithreading support when multiprocessing works just fine for most applications. You find a hot loop, you parallelize it in multiprocessing and just like that, your process runs much faster.
I do think that GIL removal is a terrible idea in general, for the reasons in the quote you provided, but at least it’s optional. I would personally not enable it in anything I maintain for several years if I didn’t have to.
I also think that polyglot code running in the same process is also a bad idea. I can understand calling C or Fortran from Python for numerical processing for example, but doing the reverse (like calling Python from Rust) is something I try to avoid at all costs. In any project I’ve worked on, if significant portions of the codebase were written in different languages, you would just use something like protobuf to specify the I/O protocol between the different languages and call them across a socket. It’s easier to maintain in my opinion since it defines a concrete boundary between the two different portions of code, and also makes it much easier to test each component separately too.
If you didn’t automatically register that requiring spawning full OS processes to scale performance immediately disqualifies a language from a whole plethora of use-cases (which is what the intellectually deficient OP tried to argue against), then I’m not sure you’re qualified to opine on the matter (hint: spawning a thread per task is already too much overhead for many workloads). And I don’t mean any disrespect to you here. Your replies were far from the worst in this thread.
Frankly this thread has been very illuminating. My perception of the average p.d user and their concrete knowledge was very inflated.
And we didn’t even get to low level stuff yet. People are already failing at the macro level. Sad.
That’s way too broad of a statement to be true in any absolute sense. It really depends on what you’re doing, and sure, there are plenty of ways to do it stupidly, but a lot of people that are smarter than you and me have thought about ways that the overhead of spawning processes can be mitigated. All I can say is that I’ve had perfectly good success using
multiprocessing.Pooland getting near perfect speedups. Is it as fast as threading? No. But it’s good enough. If it’s not good enough for you, then maybe we just have different use-cases, but without talking about concrete examples, we can’t make any specific claims.What do you want to talk about? Are you writing kernel drivers in Python or something? Why would we talk about writing low level code in Python, that sounds absurdly stupid. Most of the high performance libraries people use are written in Fortran or C. The entire field of data science uses Python, if performance were not a heavily optimized problem, then a lot of people out there must really love wasting their money on compute. Python is a glue language for high performance low level code, everybody knows this already.
At least we agree on something!
At that point just call the person messy and move on. They just want to flex their brain.
The thing is also that you can’t separate a language from its ecosystem.
Because it is possible to write the fastest programs in C/C++ and Rust, folks that actually need the fastest performance will use these languages and will go around opening pull requests to fix performance problems in commonly-used libraries.
So, you do often end up with the most performant design anyways, just because the language itself is fast on paper.
I wrote a draft of a service that would take hours to complete. when I optimized it for multithreaded operation instead of taking hours it took around 60 seconds.
write software like you write research papers. first draft > second draft > final draft > publication
I’d love that but it’s difficult when it’s not really my project and anything that is functioning well enough gets you assigned the next ticket at work.