I was in a meeting with a senior software engineer, who makes a shit ton more than me. While sharing my screen he saw flame graph I had for one program I was working on. They asked "what is that?", I was taken back, and said it's for looking at which functions are taking more time. Then I was asked "where did you find it?" I was shell shocked, didn't know how to answer that. Similar things have happened before where I taught them certain things, and they go "great find", like dude, I didn't find it just now. That's basic knowledge if you work with database.
I am not even a developer hire, I'm self learned, and because the company doesn't have many developers they gave me some of the tasks and I'm doing it because it's more fun than my job responsibilities, and when I don't have enough tasks.
You see, performance is rarely a talking point in retrospectives unless its egregious. If you say a piece of compute is struggling the solution is to always buy more compute. It is rare that anyone would think of optimization unless you're writing libraries.
Pay me to do it and I'll gladly do it. Most companies, however, don't really care much about whether the customers take an extra 100 milliseconds for every request or not. And when it's promotion time, you're often judged by how many tasks you get done, not how fast your code is.
Never understood the idea of, "if it needs to be fast, that part is in a faster language." Why not just use the faster language? Most of the libraries that have Python wrappers also come with c headers. Sometimes you wind up in the reverse situation where your dependency doesn't have a Python wrapper and now you're stuck managing silly boilerplate. Python just feels like an extra thing in the way to wrangle for little gain.
Also, hotspot-only optimization doesn't seem to have held up in reality, right? We can all agree that software is getting slower every day. The infrastructure is slow.
Because the other language is more developer-friendly or faster to write/read even if slower to execute. Some code doesn't need to be fast because it is always waiting on other things anyway.
Some languages effectively prevent whole classes of runtime failures / bad code. But, they do that by doing more which takes longer, at compile-time, run time, or both.
Some programs can't avoid graph-structured data dependencies. In that case, the simplest solution is a garbage collector, and one built into the runtime is capable of being more efficient (and less buggy) than one written for a specific program.
Anyway, there are many factors that determine which language is "best", and not all of them are objective. That's why we don't just use the fastest language. (Currently, I do all my coding in either Idris or Purescript, but I'm also unemployed and just programing for myself, for now.)
IMHO it's easier to quickly iterate with Python than with C++. If you aren't even sure what you want and you're just writing stuff, then Python is great. Is "4" true? Ofc it is.
All programming is a trade-off between what's easy for the developer and what's fast for the machine.
Sure, you could theoretically write everything in Assembly and it'd be blazingly fast; but unless you're a particularly elite developer, that process would take forever for any program more complicated than a calculator, the result would be super buggy, and those bugs would be very hard to fix.
On the other end of the spectrum, you might imagine a natural language machine learning compiler which translated directly from human prose to binary. It would be dead simple to "program" anything in; but such an application would probably be unbelievably slow, and again, have a staggering number of difficult-to-fix bugs.
Somewhere in the middle are modern programming languages that abstract away all of the stuff that's necessary but hard for humans to wrap their minds around (memory management, API interaction, network stack, etc) and let the human write clear and unambitious code to handle all of the business logic and displaying it to the user. The result won't run as blisteringly fast as writing directly in Assembly, and it won't be as quick to market as Vibes-to-ASM, but the application will be developed in a reasonable amount of time and be reasonably easy to maintain.
I worked at a place where a site had to show the number of members, but for some reason it didn't show the correct number. The reason was the query to the database was wrong, I corrected it in five minutes and the boss told me to put numbers manually, increasing them until we could display the correct query result because apparently the problem was there a long time before I started working there and it would make a bad image for the company if it was so easily corrected.
On other project a friend of mine told me about things were so slow and getting slower with time. Database didn't have keys, indexes, nothing you should expect a relational database to have.
I haven't worked in a while because of my health issues and I can assure you I'd be happier getting paid for watering plants than working with computers.
I'd add that most of the time nobody actually measured anything. at work we inherit slow sites all the time and the first guess is always "the stack", then you profile it and it's one query running per item in a loop or something like that. I had the same with my own side project, was sure I needed a bigger server and after measuring the problem was somewhere else completely. measuring first is boring but it's cheaper than any rewrite I guess
Profiling complex systems can be quite difficult. That said, I believe in the adage "Profile twice, optimize once.", adapted from the old carpenters adage of "Measure twice, cut once."
Slowness is rarely essential, but I can be far away from where you expect it.
That's what Open Telemetry is for, honestly, specifically tracing. I'm in the process of adding tracing for all of our web handlers, http client calls, database transactions/individual queries, and asynchronous jobs. Should give us a pretty good view into the performance of the system, and allow us to monitor for things like performance regressions without any dedicated profiling needed (though we certainly could add additional profiling information through Otel down the road). Since I know you're a Haskeller (recognize your handle), the hs-opentelemetryecosystem is quite solid and has integrations with a lot of libraries in the wider ecosystem, like wai, persistent, postgresql-simple, conduit, and a bunch more. I haven't needed to write too much of our own instrumentation, aside from our job system since that's a bespoke system.
Yeah we used hs-opentelemetry at my last paid position. The company was an MS shop, tho so we were using ODBC to connect to MS SQL Server which doesn't have great in-process profiling. But, at least we could figure out what quer(y/ies) were running long and then we could use the MS tools to look at the plan and fiddle with that. It was also a small org, so it's not like there was a lot of internal services in one flow -- basically everything either stayed in the Web Yesod app or in the IVR app. All our profiling could have been instrumented process profiling instead of having to use otel at all.
So, I haven't seen how easy/difficult it is to actually use otel across multiple internal service calls to satisfy one external request.
Why would that slow it down exactly? Nothing really slow about GPU accelerated graphics these days?
Would love to hear the technical reasons. You need to have UI kits for GUIs. Responsive and accessible UI kits are hard. The web solved them a decade ago and made them easier to achieve than ever before. Why invent the wheel twice?
I/O is the slowest thing ever. The more I/O dependent your app is, the slower it will be. It is not easy to make a slow web UI with zero I/O. Very easy to make a slow UI with a native toolkit and high I/O usage. Network calls are I/O. Analytics are I/O. Most enterprise apps these days demand so much analytics they effectively have spyware on their own users to optimize and A/B test against.
It's mostly because of memory cache misses. JS creates a ton of closures and has a lot of context switching. JS engines are basically a modern day miracle for how fast they are but somehow webapps are still sluggish.
Memory cache hits are destroying performance? Is this profiled or just guesswork? I don't understand how that's tied to perceived performance degradation specific to web-based toolkits like Blink and Webkit
What does that even mean? I make GUIs in web technologies, I make GUIs in godot, I make GUIs in bevy, I make GUIs in flutter, etc etc. Blink uses Skia. Flutter uses Skia. Is skia just bad? What are you even saying? What is slow about web tech, really? To me performance is almost always bad engineering choices like not understanding or handling I/O.
I haven't gotten deep enough into it to see what's wrong, but pretty much any Electron or CEF application I've used has been pretty slow, though it could be that I have a very weak PC since I only have a Ryzen 5700 and 32 gigs of DDR4 and my NVMe drives (root and home partitions being separate physical drives) are only running on PCIe 3.0, not 4.0 or 5.0. Perhaps I ought to see if things like Steam or Discord run better if I upgrade to a mid-range PC with a Ryzen 9900x, faster RAM and faster drives, but I'm not made of money.
Games run smoothly, mind you - those don't require very beefy hardware after all. It's only extremely visually and IO demanding applications like Steam or Discord that run like absolute dogshit for me. Slack used to be pretty bad too, but I don't use it these days, don't need it. Ditto for Mattermost. I have one computer dedicated to Microsoft Teams, it's got a 12th gen i7 in it which can't really handle the task, but that's just Microsoft for you, everything they've made in the last decade has been shit.
Noticeable speed? Sure. But I am so pissed if a fucking todo list app is a 100mb download and consumed 300mb memory when running, all because this fucker bundles and loads a whole browser engine to render itself.
I once did some testing comparing very simple apps built with Tauri (using system webview) and native library and the difference in memory usage was not that big. I'm looking now at a simple PDF viewer in GTK and it's using 120MB. My app written in Tauri is using 150MB. In theory native apps will use less memory when you run a lot of them at the same time but if you check the size of native Linux app they are not that tiny. They still will easily use hundredths of MB of RAM. Simple, native todo app will easily use 150MB. Yes, badly written electron app will use way more than that but you have webview tools that are really good and not that heavy.
Had the same experience when I was testing zed. Was thinking it would be a lot better since it's written in rust but there wasn't any difference in memory/CPU usage between it and VSCodium, which is electron app.
From what I remember, Vscode has quite a fair bit native code in various areas to make it perform better. So it may not be the representative Electron app for comparison.
Right now everyone is asking their AI agents to rewrite programs in Rust or C or assembly. This is fun, but it’s not a serious attempt at optimization.
C or assembly seems pointless and only for performance. But the reason people (re) write programs in Rust is because Rust as a language has a lot of guardrails that help make a program more stable, more correct. That reliability is the real reason for Rust. The performance is just a cherry on top.
This is actually exactly what you want in a language for AI. This is anecdotal from my side, but in my experience, an AI writing Rust will write far less sloppy crap than an AI writing Python.
Most of the argument against Rust has historically been that prototyping is slow and the language is a bother to write because the compiler makes it hard. But this only holds if humans are the bottleneck for writing the code! Rust therefore has all of the benefits but basically none of the downsides when having an AI write it.
But the reason people (re) write programs in Rust is because Rust as a language has a lot of guardrails that help make a program more stable, more correct. That reliability is the real reason for Rust.
Yeah, but then the Node-like atomic packaging runs contrary to optimization and security by shoving 500 MB of code in your cli-tool. And sure, the compiler optimizes 90% of it away. But that's not how you build stable software.
You could just use the standard library and refrain from using third party libraries? That's how you get a smaller binary size in just about any language.
Sure. People who do that are going to be reimplementing lots of stuff on their own and creating libraries, so they might as well leverage the work of the community.
People need to vendor their 3rd-party libraries and audit them regularly.
I agree that dependencies and package management is a real problem in programming nowadays, but it is not a problem unique to Rust. In fact, I struggle to name a single popular language nowadays that doesn't have the exact same problems.
It's not so much "But that’s not how you build stable software." It's more like "But that’s not how you build software [at all today]." Modern software is powered by loads of shared packages, that's just how all modern languages work. This is equally true for Rust and Python.
Rust still has the edge here btw. Rust libraries (crates) are often very high quality with very good documentation. The language again helps here a lot, by providing extensive tooling for automatic documentation generation. Documentation in other languages are is far less helpful or poorly written. This is also again something that helps an AI write better code (just as it helps humans write better code).
The packaging also helps elevate Rust to a high-level language, because you can build easily usable abstractions in packages that can be used in simple programs. All the complexity can be hidden away in a crate and suddenly Rust feels more like Python. I think that's actually a good thing from package managers.
It’s not so much “But that’s not how you build stable software.” It’s more like “But that’s not how you build software [at all today].” Modern software is powered by loads of shared packages, that’s just how all modern languages work. This is equally true for Rust and Python.
You're not wrong - all libraries with automated dependency packaging do have this problem. But you're downplaying the scale by a lot. Javascript dependency graphs are absolutely massive. Python has a decent standard library that reduces the number of shared packages by quite a bit. There are definitely downsides to having a large standard library like Python has, but it does significantly reduce the probability of a supply chain attack compared to Javascript.
I can't comment on Rust personally, since I don't have much experience with the ecosystem.
Sure, yes, Rust has lots of quality libraries too. I'm thinking of doing the core in D and the GUI in Rust Slint. Plug-in protocol interface modules can be written in whatever, but Rust has some interesting libraries.
Ship in the minimum amount of time possible, by any means, to be first to market. And this means poor design and smooshing together all kind of fat general-purpose frameworks and libraries to get something out the door.
Sure, it's slow. Google's landing page is 4 MB for a small graphic, a text form, and some buttons. But what are you going to do? Not use it? They won. They don't have to fix shit.
And now with LLMs they can produce bloat faster than ever and pay even less attention to speed or quality.
Sure, it’s slow. Google’s landing page is 4 MB for a small graphic, a text form, and some buttons. But what are you going to do? Not use it? They won. They don’t have to fix shit.
This neglects to include the massive amount of additional front-end code Google (and other large tech companies) toss on their webpages for things that are purely for their own benefit while being of zero or negative value to the users. Mouse tracking, analytics, fingerprinting, and all kinds of other harmful content that tech companies put out go a long way towards reaching that 4MB figure.
Yeah, I long ago switched to ddg and I also turn off the ddg ai stuff. I hear the paid search is also out-performing Google for people that care their search results are accurate.
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.
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.
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
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:
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.
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.
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.
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.
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.
Software engineer and can confirm this is mostly the case. Adding a spinner or cute animation to placate users is way easier than solving fundamental issues. There are definitely teams out there that absolutely care about performance but mostly in large scale scenarios where an extra 10ms per record adds up to 3 extra hours to finish a batch.
He is right in many aspects. However, for example Guile, Racket or SBCL Lisp are a lot faster than Python, and they are more powerful than Python while being much simpler, which makes them very interesting for prototyping algorithms.
The ideal combo for such things would be a powerful interactive language with debugging capabilities combined with Rust, perhaps even a language similar to Rust. I do not know of any easy solution for that, but it could be made work with Rust's macro system (since the above languages all provide C ABI FFI).
Also,most of design happens when a program is written first. It is hard to re-design a larger program later, which might be one reason to re-write it. So maybe the main reason for rewriting is to get a better design, not the faster language - the faster language might be an additional reason.
Also, LLMs can produce terribly bloated Rust code - not only by a factor ten larger, but also much slower.
Also, CRUD apps are uninteresting to many programming enthusiasts, and for companies, optimizing them is only interesting if it saves them money.
Yes and no. It's not usually the fault of the programming language.
But programming languages have a unique ability: The design of the language itself can and will instill bad or good habits into the code of oneself. These languages are designed pretty deliberately, so those habits are a direct consequence of the design of a language.
In fact, Sean Goedecke's own C-to-Rust example makes this point implicitly: Cantrill's port got faster not because the redesign was really clever, but because Rust's borrow checker and standard library actively steered him toward a more cache friendly Binary tree. There are probably many more examples out there that had a real world impact.
There are no bad languages, every language has its place somewhere. But design decisions matter.
I always wonder who is the target audience of such shallow fallacy-filled pretend-insightful faux-wisdom. But then I remember that most people waste a lot of time following aggregator/discussion sites are young impressionable enthusiasts who don't know much.
If you think about it, this was also true in the 80s, but because the hardware sucked. Good thing we learned better design so we can have things like AI
Well that depends. Are you going with micro services because it's fashionable or because different parts of your backend work with completely different data and don't need to communicate with eachother that much?
I'm of the opinion that anything that needs to share one database should be one service, and things that are so easily detached that you can just plop the tables over into a separate database, can be separate services, because that will allow you to scale up one without scaling the other and one database's I/O won't get in the way of the other database's I/O (assuming they're on different machines of course). I'd say:
My perspective is a self hosting hobbyist I noticed for those running on more reliable vps servers with rollbacks being a last resort the higher requirements are not as important.
That's as a self-hosting hobbyist. Sqlite is great for that. It stops being great when you have thousands of users, and good luck using it with millions.
Choice of language is part of the design, but it's probably more "runtime" than the language itself as it could just be a spec with multiple implementations.
93 replies
Has everyone forgotten the art of creating or using performance profiling tools
I was in a meeting with a senior software engineer, who makes a shit ton more than me. While sharing my screen he saw flame graph I had for one program I was working on. They asked "what is that?", I was taken back, and said it's for looking at which functions are taking more time. Then I was asked "where did you find it?" I was shell shocked, didn't know how to answer that. Similar things have happened before where I taught them certain things, and they go "great find", like dude, I didn't find it just now. That's basic knowledge if you work with database.
I am not even a developer hire, I'm self learned, and because the company doesn't have many developers they gave me some of the tasks and I'm doing it because it's more fun than my job responsibilities, and when I don't have enough tasks.
You see, performance is rarely a talking point in retrospectives unless its egregious. If you say a piece of compute is struggling the solution is to always buy more compute. It is rare that anyone would think of optimization unless you're writing libraries.
Pay me to do it and I'll gladly do it. Most companies, however, don't really care much about whether the customers take an extra 100 milliseconds for every request or not. And when it's promotion time, you're often judged by how many tasks you get done, not how fast your code is.
Never understood the idea of, "if it needs to be fast, that part is in a faster language." Why not just use the faster language? Most of the libraries that have Python wrappers also come with c headers. Sometimes you wind up in the reverse situation where your dependency doesn't have a Python wrapper and now you're stuck managing silly boilerplate. Python just feels like an extra thing in the way to wrangle for little gain.
Also, hotspot-only optimization doesn't seem to have held up in reality, right? We can all agree that software is getting slower every day. The infrastructure is slow.
All feels like cope, through and through.
Because the other language is more developer-friendly or faster to write/read even if slower to execute. Some code doesn't need to be fast because it is always waiting on other things anyway.
Some languages effectively prevent whole classes of runtime failures / bad code. But, they do that by doing more which takes longer, at compile-time, run time, or both.
Some programs can't avoid graph-structured data dependencies. In that case, the simplest solution is a garbage collector, and one built into the runtime is capable of being more efficient (and less buggy) than one written for a specific program.
Anyway, there are many factors that determine which language is "best", and not all of them are objective. That's why we don't just use the fastest language. (Currently, I do all my coding in either Idris or Purescript, but I'm also unemployed and just programing for myself, for now.)
IMHO it's easier to quickly iterate with Python than with C++. If you aren't even sure what you want and you're just writing stuff, then Python is great. Is "4" true? Ofc it is.
All programming is a trade-off between what's easy for the developer and what's fast for the machine.
Sure, you could theoretically write everything in Assembly and it'd be blazingly fast; but unless you're a particularly elite developer, that process would take forever for any program more complicated than a calculator, the result would be super buggy, and those bugs would be very hard to fix.
On the other end of the spectrum, you might imagine a natural language machine learning compiler which translated directly from human prose to binary. It would be dead simple to "program" anything in; but such an application would probably be unbelievably slow, and again, have a staggering number of difficult-to-fix bugs.
Somewhere in the middle are modern programming languages that abstract away all of the stuff that's necessary but hard for humans to wrap their minds around (memory management, API interaction, network stack, etc) and let the human write clear and unambitious code to handle all of the business logic and displaying it to the user. The result won't run as blisteringly fast as writing directly in Assembly, and it won't be as quick to market as Vibes-to-ASM, but the application will be developed in a reasonable amount of time and be reasonably easy to maintain.
I worked at a place where a site had to show the number of members, but for some reason it didn't show the correct number. The reason was the query to the database was wrong, I corrected it in five minutes and the boss told me to put numbers manually, increasing them until we could display the correct query result because apparently the problem was there a long time before I started working there and it would make a bad image for the company if it was so easily corrected.
On other project a friend of mine told me about things were so slow and getting slower with time. Database didn't have keys, indexes, nothing you should expect a relational database to have.
I haven't worked in a while because of my health issues and I can assure you I'd be happier getting paid for watering plants than working with computers.
I'd add that most of the time nobody actually measured anything. at work we inherit slow sites all the time and the first guess is always "the stack", then you profile it and it's one query running per item in a loop or something like that. I had the same with my own side project, was sure I needed a bigger server and after measuring the problem was somewhere else completely. measuring first is boring but it's cheaper than any rewrite I guess
Profiling complex systems can be quite difficult. That said, I believe in the adage "Profile twice, optimize once.", adapted from the old carpenters adage of "Measure twice, cut once."
Slowness is rarely essential, but I can be far away from where you expect it.
That's what Open Telemetry is for, honestly, specifically tracing. I'm in the process of adding tracing for all of our web handlers, http client calls, database transactions/individual queries, and asynchronous jobs. Should give us a pretty good view into the performance of the system, and allow us to monitor for things like performance regressions without any dedicated profiling needed (though we certainly could add additional profiling information through Otel down the road). Since I know you're a Haskeller (recognize your handle), the
hs-opentelemetryecosystem is quite solid and has integrations with a lot of libraries in the wider ecosystem, likewai,persistent,postgresql-simple,conduit, and a bunch more. I haven't needed to write too much of our own instrumentation, aside from our job system since that's a bespoke system.Yeah we used hs-opentelemetry at my last paid position. The company was an MS shop, tho so we were using ODBC to connect to MS SQL Server which doesn't have great in-process profiling. But, at least we could figure out what quer(y/ies) were running long and then we could use the MS tools to look at the plan and fiddle with that. It was also a small org, so it's not like there was a lot of internal services in one flow -- basically everything either stayed in the Web Yesod app or in the IVR app. All our profiling could have been instrumented process profiling instead of having to use otel at all.
So, I haven't seen how easy/difficult it is to actually use otel across multiple internal service calls to satisfy one external request.
Nah, software is slow because it runs a web engine for GUI.
God, this again.
Why would that slow it down exactly? Nothing really slow about GPU accelerated graphics these days?
Would love to hear the technical reasons. You need to have UI kits for GUIs. Responsive and accessible UI kits are hard. The web solved them a decade ago and made them easier to achieve than ever before. Why invent the wheel twice?
I/O is the slowest thing ever. The more I/O dependent your app is, the slower it will be. It is not easy to make a slow web UI with zero I/O. Very easy to make a slow UI with a native toolkit and high I/O usage. Network calls are I/O. Analytics are I/O. Most enterprise apps these days demand so much analytics they effectively have spyware on their own users to optimize and A/B test against.
It's mostly because of memory cache misses. JS creates a ton of closures and has a lot of context switching. JS engines are basically a modern day miracle for how fast they are but somehow webapps are still sluggish.
Memory cache hits are destroying performance? Is this profiled or just guesswork? I don't understand how that's tied to perceived performance degradation specific to web-based toolkits like Blink and Webkit
It still adds a lot of layers between the user and the processor.
What does that even mean? I make GUIs in web technologies, I make GUIs in godot, I make GUIs in bevy, I make GUIs in flutter, etc etc. Blink uses Skia. Flutter uses Skia. Is skia just bad? What are you even saying? What is slow about web tech, really? To me performance is almost always bad engineering choices like not understanding or handling I/O.
So that means every single developer that has ever used Electron or CEF for something, has been making bad engineering choices?
You may have something there.
Why is how nodejs or cef does I/O worse than any other GUI toolkit's I/O layer?
I haven't gotten deep enough into it to see what's wrong, but pretty much any Electron or CEF application I've used has been pretty slow, though it could be that I have a very weak PC since I only have a Ryzen 5700 and 32 gigs of DDR4 and my NVMe drives (root and home partitions being separate physical drives) are only running on PCIe 3.0, not 4.0 or 5.0. Perhaps I ought to see if things like Steam or Discord run better if I upgrade to a mid-range PC with a Ryzen 9900x, faster RAM and faster drives, but I'm not made of money.
Games run smoothly, mind you - those don't require very beefy hardware after all. It's only extremely visually and IO demanding applications like Steam or Discord that run like absolute dogshit for me. Slack used to be pretty bad too, but I don't use it these days, don't need it. Ditto for Mattermost. I have one computer dedicated to Microsoft Teams, it's got a 12th gen i7 in it which can't really handle the task, but that's just Microsoft for you, everything they've made in the last decade has been shit.
"layers" don't necessarily make things appreciably slow.
Noticeable speed? Sure. But I am so pissed if a fucking todo list app is a 100mb download and consumed 300mb memory when running, all because this fucker bundles and loads a whole browser engine to render itself.
I therefore do think tech stack matters as well.
Web development and using browser renderers for GUIs is one of my most hated aspects of modern software. 🤢
Sorry guys, back in 2008, I asked a monkey's paw for better first party software support for desktop Linux, and this is what we got.
I once did some testing comparing very simple apps built with Tauri (using system webview) and native library and the difference in memory usage was not that big. I'm looking now at a simple PDF viewer in GTK and it's using 120MB. My app written in Tauri is using 150MB. In theory native apps will use less memory when you run a lot of them at the same time but if you check the size of native Linux app they are not that tiny. They still will easily use hundredths of MB of RAM. Simple, native todo app will easily use 150MB. Yes, badly written electron app will use way more than that but you have webview tools that are really good and not that heavy.
Had the same experience when I was testing zed. Was thinking it would be a lot better since it's written in rust but there wasn't any difference in memory/CPU usage between it and VSCodium, which is electron app.
From what I remember, Vscode has quite a fair bit native code in various areas to make it perform better. So it may not be the representative Electron app for comparison.
That would be 20 kB, 30 kB, 40 kB, I don't think you meant that.
C or assembly seems pointless and only for performance. But the reason people (re) write programs in Rust is because Rust as a language has a lot of guardrails that help make a program more stable, more correct. That reliability is the real reason for Rust. The performance is just a cherry on top.
This is actually exactly what you want in a language for AI. This is anecdotal from my side, but in my experience, an AI writing Rust will write far less sloppy crap than an AI writing Python.
Most of the argument against Rust has historically been that prototyping is slow and the language is a bother to write because the compiler makes it hard. But this only holds if humans are the bottleneck for writing the code! Rust therefore has all of the benefits but basically none of the downsides when having an AI write it.
Yeah, but then the Node-like atomic packaging runs contrary to optimization and security by shoving 500 MB of code in your cli-tool. And sure, the compiler optimizes 90% of it away. But that's not how you build stable software.
You could just use the standard library and refrain from using third party libraries? That's how you get a smaller binary size in just about any language.
Sure. People who do that are going to be reimplementing lots of stuff on their own and creating libraries, so they might as well leverage the work of the community.
People need to vendor their 3rd-party libraries and audit them regularly.
I agree that dependencies and package management is a real problem in programming nowadays, but it is not a problem unique to Rust. In fact, I struggle to name a single popular language nowadays that doesn't have the exact same problems.
It's not so much "But that’s not how you build stable software." It's more like "But that’s not how you build software [at all today]." Modern software is powered by loads of shared packages, that's just how all modern languages work. This is equally true for Rust and Python.
Rust still has the edge here btw. Rust libraries (crates) are often very high quality with very good documentation. The language again helps here a lot, by providing extensive tooling for automatic documentation generation. Documentation in other languages are is far less helpful or poorly written. This is also again something that helps an AI write better code (just as it helps humans write better code).
The packaging also helps elevate Rust to a high-level language, because you can build easily usable abstractions in packages that can be used in simple programs. All the complexity can be hidden away in a crate and suddenly Rust feels more like Python. I think that's actually a good thing from package managers.
You're not wrong - all libraries with automated dependency packaging do have this problem. But you're downplaying the scale by a lot. Javascript dependency graphs are absolutely massive. Python has a decent standard library that reduces the number of shared packages by quite a bit. There are definitely downsides to having a large standard library like Python has, but it does significantly reduce the probability of a supply chain attack compared to Javascript.
I can't comment on Rust personally, since I don't have much experience with the ecosystem.
Sure, yes, Rust has lots of quality libraries too. I'm thinking of doing the core in D and the GUI in Rust Slint. Plug-in protocol interface modules can be written in whatever, but Rust has some interesting libraries.
Ship in the minimum amount of time possible, by any means, to be first to market. And this means poor design and smooshing together all kind of fat general-purpose frameworks and libraries to get something out the door.
Sure, it's slow. Google's landing page is 4 MB for a small graphic, a text form, and some buttons. But what are you going to do? Not use it? They won. They don't have to fix shit.
And now with LLMs they can produce bloat faster than ever and pay even less attention to speed or quality.
"The goal was never quality software."
This neglects to include the massive amount of additional front-end code Google (and other large tech companies) toss on their webpages for things that are purely for their own benefit while being of zero or negative value to the users. Mouse tracking, analytics, fingerprinting, and all kinds of other harmful content that tech companies put out go a long way towards reaching that 4MB figure.
...I don't use Goog's search, just like probably many people on Lemmy.
Yeah, I long ago switched to ddg and I also turn off the ddg ai stuff. I hear the paid search is also out-performing Google for people that care their search results are accurate.
Google is a bad example, historically the landing page has been interestingly optimised.
Lots of corporate websites are multi-hundred MB things though you are right.
Edit I take it back, the worst ones I checked have been redesigned
I'd like you to name 1 that's multi-hundred MB.
Can't, I was thinking of MSN.com but they had a redesign sometime, they come in at 5.6mb now
I saw something where the NYT webside takes up over 100MB if RAM.
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.
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.
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:
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!
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:
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
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.
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.
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.
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.
Software engineer and can confirm this is mostly the case. Adding a spinner or cute animation to placate users is way easier than solving fundamental issues. There are definitely teams out there that absolutely care about performance but mostly in large scale scenarios where an extra 10ms per record adds up to 3 extra hours to finish a batch.
He is right in many aspects. However, for example Guile, Racket or SBCL Lisp are a lot faster than Python, and they are more powerful than Python while being much simpler, which makes them very interesting for prototyping algorithms.
The ideal combo for such things would be a powerful interactive language with debugging capabilities combined with Rust, perhaps even a language similar to Rust. I do not know of any easy solution for that, but it could be made work with Rust's macro system (since the above languages all provide C ABI FFI).
Also,most of design happens when a program is written first. It is hard to re-design a larger program later, which might be one reason to re-write it. So maybe the main reason for rewriting is to get a better design, not the faster language - the faster language might be an additional reason.
Also, LLMs can produce terribly bloated Rust code - not only by a factor ten larger, but also much slower.
Also, CRUD apps are uninteresting to many programming enthusiasts, and for companies, optimizing them is only interesting if it saves them money.
Yes and no. It's not usually the fault of the programming language.
But programming languages have a unique ability: The design of the language itself can and will instill bad or good habits into the code of oneself. These languages are designed pretty deliberately, so those habits are a direct consequence of the design of a language. In fact, Sean Goedecke's own C-to-Rust example makes this point implicitly: Cantrill's port got faster not because the redesign was really clever, but because Rust's borrow checker and standard library actively steered him toward a more cache friendly Binary tree. There are probably many more examples out there that had a real world impact.
There are no bad languages, every language has its place somewhere. But design decisions matter.
Malbolge. ;)
Except for python.
Python copium.
I'd argue a combination of bad design and/or bad implementation, which i would consider different things.
It's a difference that becomes more pronounced the larger the team grows.
A somewhat reasonable design can be absolutely destroyed by a poor implementation of that design
I always wonder who is the target audience of such shallow fallacy-filled pretend-insightful faux-wisdom. But then I remember that most people waste a lot of time following aggregator/discussion sites are young impressionable enthusiasts who don't know much.
If you think about it, this was also true in the 80s, but because the hardware sucked. Good thing we learned better design so we can have things like AI
Bullshit. My experience of Python is that only a small subset of programs are actually IO bound.
Compare frameworks more than languages.
Hyper > Gin > FastAPI > NextJS > Laravel > Drupal
Qt > GTK > Tauri > Fyne > Wails > Electron > React Native
Sqlite ~ Pgsql > mariadb
One docker container > ten micro services
Environment variables > ini > database config table
Edit: voters have spoken sqlite and pg are now on equal footing.
Well that depends. Are you going with micro services because it's fashionable or because different parts of your backend work with completely different data and don't need to communicate with eachother that much?
I'm of the opinion that anything that needs to share one database should be one service, and things that are so easily detached that you can just plop the tables over into a separate database, can be separate services, because that will allow you to scale up one without scaling the other and one database's I/O won't get in the way of the other database's I/O (assuming they're on different machines of course). I'd say:
Microservices ~ monolith > Distributed monolith
Distributed monoliths suck.
BRB, gonna tell my boss we should move our data warehouse to sqlite.
He said "simple comparisons of technologies on a single metric are stupid."
Disagree. Different tools for different jobs.
My perspective is a self hosting hobbyist I noticed for those running on more reliable vps servers with rollbacks being a last resort the higher requirements are not as important.
That's as a self-hosting hobbyist. Sqlite is great for that. It stops being great when you have thousands of users, and good luck using it with millions.
Choice of language is part of the design, but it's probably more "runtime" than the language itself as it could just be a spec with multiple implementations.