Live data from Hacker News

Comparison of Rust async and Linux thread context switch time and memory use

github.com

21–30 of 201 posts

Re: Comparison of Rust async and Linux thread context switch time and memory use

#21
post #7

I am not surprised that the cost of context switching due to I/O readiness can often be roughly equal between async tasks and kernel threads. Normal blocking I/O can be surprisingly efficient because of various factors, such as a reduced need for system calls. Think about it this way—if you have a user-space thread which wakes up due to I/O readiness, then this means that the relevant kernel thread woke up from epoll…

Then why is it that IO-heavy benchmarks such as the Techempower web benchmark are dominated by async frameworks? The fastest results there are all from async frameworks [1]. And among Rust frameworks the same pattern holds. The fastest Rust frameworks are async while a synchronous frmework such as Rocket is about 20x slower. [1] https://www.techempower.com/benchmarks/#section=data-r20&hw=... [2] https://www.techempow…

I'd argue that it's because even though blocking IO is cheaper, it's very difficult to maximise performance in a multithreaded/concurrent context.

You could make faster code with it but I wouldn't want to maintain it and you'd have to throw an obscene amount of man hours at it to get that performance.

Re: Comparison of Rust async and Linux thread context switch time and memory use

#22
post #9

Earlier quoted context omitted.

io_uring will help a lot here.

Well, it can, but not always. Remember that if you’re waiting for an event to arrive, that generally involves a syscall, the thread being put to sleep, and then the thread being woken up. Any time you’re doing that, think, “Could I just replace this polling system with a call to read()?” What io_uring does do is provide a way to poll without needing to wait, but if you haven’t received new events when you poll, you’r…

io_uring is specifically designed so that zero system calls are necessary while the system is busy. Userspace and the kernel both update ring buffers, and ring buffers can be checked and drained without entering the kernel at all.

Re: Comparison of Rust async and Linux thread context switch time and memory use

#23
post #5

That's a huge help. I only need about 20 threads in Rust, some of which are compute-bound. So involving "async" is totally the wrong tool for the job. Goodbye, Tokio.

Sorry, what does tokio have to do with "async"? The default implementation uses posix threads, no?

Re: Comparison of Rust async and Linux thread context switch time and memory use

#25
post #16
post #7

I am not surprised that the cost of context switching due to I/O readiness can often be roughly equal between async tasks and kernel threads. Normal blocking I/O can be surprisingly efficient because of various factors, such as a reduced need for system calls. Think about it this way—if you have a user-space thread which wakes up due to I/O readiness, then this means that the relevant kernel thread woke up from epoll…

Linux is likely many years from having anything approaching a fully asynchronous system call interface, if anyone was willing to work on it (io_uring makes a huge dent but I don't think it's intending to reimplement everything). Even where async kernel interfaces exist, without reworking of the kernel-internal implementation still there is often the need for a thread for the kernel side to execute on. For example IIR…

I'm not sure about io_uring not reimplementing everything.. it seems to be gaining more and more scope.

Re: Comparison of Rust async and Linux thread context switch time and memory use

#26

How does Rust async compare to Goroutine, Erlang threads, Javascript async, Java async in performance and memory usage? Is there any benchmarks for that?

Which rust async runtime are you referring to?

Say Tokio, the async runtime used in OP's article.

Re: Comparison of Rust async and Linux thread context switch time and memory use

#27

Earlier quoted context omitted.

Well, it can, but not always. Remember that if you’re waiting for an event to arrive, that generally involves a syscall, the thread being put to sleep, and then the thread being woken up. Any time you’re doing that, think, “Could I just replace this polling system with a call to read()?” What io_uring does do is provide a way to poll without needing to wait, but if you haven’t received new events when you poll, you’r…

io_uring is specifically designed so that zero system calls are necessary while the system is busy. Userspace and the kernel both update ring buffers, and ring buffers can be checked and drained without entering the kernel at all.

Yes, that’s what “if you haven’t received new events when you poll” means.

Re: Comparison of Rust async and Linux thread context switch time and memory use

#28

How does Rust async compare to Goroutine, Erlang threads, Javascript async, Java async in performance and memory usage? Is there any benchmarks for that?

Rust doesn't have a standard async runtime, so the question would be "how does tokio compare to goroutine, etc..." since that's the most popular one.

Looking at the techempower benchmarks, the projects using tokio generally outperform Go, Java, so I'm guessing it's on par or better.

Hypothetically, you could port goroutines exact behavior to rust and use that as your wanted to too.

Re: Comparison of Rust async and Linux thread context switch time and memory use

#30
post #5

That's a huge help. I only need about 20 threads in Rust, some of which are compute-bound. So involving "async" is totally the wrong tool for the job. Goodbye, Tokio.

Sorry, what does tokio have to do with "async"? The default implementation uses posix threads, no?

[deleted]
Post reply on HN