Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I don't think io_uring and ebpf will revolutionize programming on Linux. In fact I hope they don't. The most important aspect of a program is correctness, not speed. Writing asynchronous code is much harder to get right.

Sure, I still write asynchronous code. Mostly to find out if I can. My experience has been that async code is hard to write, is larger, hard to read, hard to verify as correct and may not even be faster for many common use cases.

I also wrote some kernel code, for the same reason. To find out if I could. Most programmers have this drive, I think. They want to push themselves.

And sure, go for it! Just realize that you are experimenting, and you are probably in over your head.

Most of us are most of the time.

Someone will have to be able to fix bugs in your code when you are unavailable. Consider how hard it is to maintain other people's code even if it is just a well-formed, synchronous series of statements. Then consider how much worse it is if that code is asynchronous and maybe has subtle timing bugs, side channels and race conditions.

If I haven't convinced you yet, let me try one last argument.

I invite you to profile how much actual time you spend doing syscalls. Syscalls are amazingly well optimized on Linux. The overhead is practically negligible. You can do hundreds of thousands of syscalls per second, even on old hardware. You can also easily open thousands of threads. Those also scale really well on Linux.



I don't know what kind of programming you're doing, but in network apps, if you have a thread per client and lots of clients (like a web server), you end up with lots of threads waiting on responses from slow clients, and that takes up memory. The time blocked on the syscall has nothing to do with your own machine's performance.

But on the other hand, if your server is behind a buffering proxy so it's not streaming directly over the Internet, it might not be a problem.


> But on the other hand, if your server is behind a buffering proxy so it's not streaming directly over the Internet, it might not be a problem.

This is one instance of a larger pattern I've been noticing. When using some languages (like Python and Ruby) in the natural, blocking way, a back-end web application typically needs multiple processes per machine, because it doesn't handle many concurrent requests per process. Combine this with the fact that each thread has to block while waiting on the client, and you have to add more complexity around the application server processes to regain efficiency. The proxy in front of those servers is one example. Another is an external database connection pool like PgBouncer. Speaking of the database, to avoid wasting memory while waiting on it, you may end up introducing caching sooner than you otherwise would. And when you do, the cache will be an external component like Redis, so all of your many processes can use it. Or you might use a background job queue just to avoid tying up one of your precious blocking threads, even for something that has to happen right away (e.g. sending email). And so on.

Contrast that with something like Go or Erlang (and by extension Elixir), where the runtime offers cheap concurrency that can fully use all of your cores in a single process, built on lightweight userland threads and asynchronous I/O, while the language lets you write straightforward, sequential code. In such an environment, a lot of the operational complexity that I described above can just go away. Simple code and simple ops -- seems like a winning combination to me.


Cooperative multitasking is much easier to implement and administer than preemptive multitasking, and always has been. But there are cases where it isn't good enough, and if you hit those then you need a system that can do preemptive multitasking gracefully - which often means you end up with just as much complexity as if you'd used preemptive multitasking from the start, but with the complex parts being less well-tested.


>"But there are cases where it isn't good enough, and if you hit those then you need a system that can do preemptive multitasking gracefully ..."

What are some of those use cases where userland threads are no longer good enough? In what areas do they fall short?


Essentially any time you have to run something that's not completely trusted to not block a thread - which could be user-supplied code (or "code" - matching a regex is unsafe in most implementations, rendering PostScript is famously Turing-complete) or just a third-party dependency.

At my first job we had a prototype that performed 2x faster (on average) by using Go-style async, but we couldn't trust our libraries enough to eliminate bugs from blocking dispatcher threads. So we stuck with traditional multithreading.


It's all true, and yet most webservers were like that 20 years ago - and they still managed to run even fairly high-traffic websites on hardware much less powerful than what we have today. I would argue that >90% of the web doesn't really need the extra throughput that async gives you at the cost of extra complexity.


Writing asynchronous code is trying to fix how your code is executed in the code itself. It is the wrong solution for a real problem.

But I think what many people get wrong (not the person I'm replying to) is that how you write code and how you execute code does not have to be the same.

This is essentially why google made their N:M threading patches: https://lore.kernel.org/lkml/20200722234538.166697-1-posk@po...

This is why Golang uses goroutines. This is why Javascript made async/await. This is why project loom exists. This is why erlang uses erlang processes.

All of these initiatives make it possible to write synchronous code and execute it as if it was written asynchronously.

And I think all of this also makes it clear that how you write code and how code is executed is not the same, so yes, I'm in agreement with the person I'm replying to, I don't think this will change how code is written that much, because this can't make writing code asynchronously any less of a bad idea than it is now.


> This is why Golang uses goroutines. This is why Javascript made async/await. This is why project loom exists. This is why erlang uses erlang processes.

JavaScript async/await is different from the others. It requires two colors of functions [1], and it conflates how the code is written with how it's executed, so it has the same problem you were talking about at the start of your comment.

Also, JavaScript async/await is suboptimal in that it's ultimately built on top of unstructured callbacks. Or, as Nathaniel J. Smith put it in a post about Python's asyncio module, which has the same problem, "Your async/await functions are dumplings of local structure floating on top of callback soup, and this has far-reaching implications for the simplicity and correctness of your code." [2] That whole post is well worth a read IMO.

[1]: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...

[2]: https://vorpus.org/blog/some-thoughts-on-asynchronous-api-de...


> JavaScript async/await is different from the others.

It allows me to write synchronous code and execute it asynchronously. The mechanism is different - but the purpose is the same. I'm not endorsing the implementation. But I do use it, because it is way better than writing asynchronous code.


What a wonderfully dogmatic comment that completely misses the point of io_uring.


Given the article's over-the-top opening, I think it's good to have a reality check that reminds us of fundamentals like correctness over speed, and clarity over cleverness.


io_uring is correct. It's nothing clever - in fact, it's quite boring. It is specifically meant for applications that must handle high volumes of asynchronous I/O.

Yes, believe it or not, you can achieve correctness and speed, together, without compromise.


For 99,99% of Linux programming io_uring and eBPF do not have a point and developers couldn't care less about them.


Care to shed some lights on the points of io_uring the OP misses? (honestly interested)


What are your thoughts on Rust?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: