Live data from Hacker News

Maybe Rust isn’t a good tool for massively concurrent, userspace software

bitbashing.io

551–560 of 624 posts

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#551

Earlier quoted context omitted.

The safety argument is actually the reason why you can use Rust in those cases to begin with. If it was C or C++ you simply couldn't use it for things like webservers due to the safety problems inherent to these languages. So Rust creeps into the part of the market that used to be exclusive to GC languages.

What do you think nginx and Apache are written in?

How few severe vulnerabilities and other major defects (memory corruption or crashes) do you think Nginx and Apache have had over the years?

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#552
post #548

Earlier quoted context omitted.

Async as a paradigm seems so against what GP was discussing. If I understood, and from my experience, we're talking more about concurrent execution with carefully-designed priorities, locks, and timing requirements. This is closer to the embedded / systems-level concurrency, if I understand it right. Are we really expecting a coroutine/ async style to just lift into this world?

Threads are for doing your own work in parallel. Async is for waiting on others to do their work in parallel. Your own work would be some CPU-intensive operations you can logically divide and conquer. Others' work would be waiting for file I/O from the OS, waiting for a DB result set following a query, waiting for a gRPC response, etc. Conceptually quite distinct, and there are demonstrated advantages and drawbacks t…

All correct. An additional comment is that, when I was coming up, parallelism in its many forms was of the variety "I need to do this job in parallel" or "I need to handle exactly 32 concurrent workers". After web & such, it was common to just think of paralellism as "I declare this one method as returning a promise" and then "async def", which semantically is very different than managing threads. As pointed out, it's now more like "This function is basically a server for any and all uncontrolled calls from elsewhere".

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#553
post #352

Earlier quoted context omitted.

Yes actually it is solved. If you stick to async then it cannot deadlock (in this way) because you yield execution to await.

> Yes actually it is solved. If you stick to async then it cannot deadlock (in this way) because you yield execution to await. Maybe I'm misunderstanding what you are saying. I use the word "_implementation_type_" below to mean "either implemented as option 1 or option 2 from my post above." With current asynchronous implementations (like JS, Rust, etc), any time you use `await` or similar, that statement may never r…

I'm referring to the situation where a synchronous wait consumes the thread pool, preventing any further work.

A is sychrounously waiting B which is awaiting C which could complete but never gets scheduled because A is holding onto the only thread. Its a very common situation when you mix sync and async and you're working in a single threaded context, like UI programming with async. Of course it can also cause starvation and deadlock in a multithreaded context as well but the single thread makes the pitfall obvious.

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#554
post #542

Earlier quoted context omitted.

You need to `block_on` only if you need to block on async code. But you don't need to block on order to run async code. You can spawn async code without blocking just fine and there is no risk of deadlocks.

Now you lose determinism in tear down though.

Ok, in a very, very rare case (so far never happened to me) when I really need to await an async operation in the destructor, I just define an additional async destructor, call it explicitly and await it. Maybe it's not very elegant but gets the job done and is quite readable as well.

And this would be basically what you have to do in Go anyways - you need to explicitly use defer if you want code to run on destruction, with the caveat that in Go nothing stops you from forgetting to call it, when in Rust I can at least have a deterministic guard that would panic if I forget to call the explicit destructor before the object getting out of scope.

BTW async drop is being worked on in Rust, so in the future this minor annoyance will be gone

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#555

Earlier quoted context omitted.

UI in Rust without inheritance is tricky. There's still no great UI framework written in Rust yet, though not for lack of trying! I'm interested to see how Bevy's UI turns out. They're currently exploring the design space and requirements for production-grade UI, actually.

Wouldn’t something akin to swift UI work well in this situation? I can understand that not having a “component” class to inherit would make building custom components difficult, but if most layout and skinning can be accomplish via functions then you can sidestep the issue for most cases I think…

I think people are looking to SwiftUI for inspiration. It'll still take some time to build and evaluate these solutions.

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#556
post #542

Earlier quoted context omitted.

Now you lose determinism in tear down though.

Ok, in a very, very rare case (so far never happened to me) when I really need to await an async operation in the destructor, I just define an additional async destructor, call it explicitly and await it. Maybe it's not very elegant but gets the job done and is quite readable as well. And this would be basically what you have to do in Go anyways - you need to explicitly use defer if you want code to run on destructio…

Yes I am aware of async drop proposals. And the point is not to handle a single value being dropped but to facilitate invariants during an abrupt tear down. Today, when I am writing a task which needs tear down I need to hand it a way to signal a “nice” shutdown, wait some time, and then hard abort it.

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#557

Earlier quoted context omitted.

To run async in Drop in rust, you need to use block_on() as you can't natively await (unlike in Go). This is the "blocking on Drop" mentioned and can result in deadlocks if the async logic is waiting on the runtime to advance, but the block_on() is preventing the runtime thread from advancing. Something like `async fn drop(&mut self)` is one way to avoid this if Rust supported it.

You need to `block_on` only if you need to block on async code. But you don't need to block on order to run async code. You can spawn async code without blocking just fine and there is no risk of deadlocks.

1) That's no longer "running async code in Drop" as it's spawned/detached and semantically/can run outside the Drop. This distinction is important for something like `select` which assumes all cancellation finishes in Drop. 2) This doesn't address the efficiency concern of using borrowed memory in the Future. You have to either reference count or own the memory used by the Future for the "spawn in Drop" scheme to work for cleanup. 3) Even if you define an explicit/custom async destructor, Rust doesn't have a way to syntactically defer its execution like Go and Zig do so you'd end up having to call it on all exit points which is error prone like C (would result in a panic instead of a leak/UB, but that can be equally undesirable). 4) Is there anywhere one can read up on the work being done for async Drop in Rust? Was only able to find this official link but it seems to still have some unanswered questions (https://rust-lang.github.io/async-fundamentals-initiative/ro...)

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#558

Earlier quoted context omitted.

It doesn't really matter, there doesn't exist a problem space where both Rust and Python are reasonable choices. Case in point, I once wrote a program to take a 360 degree image and rotate it so that the horizon followed the horizontal line along the middle, and it faced north. I wrote it in python first and running it on a 2k image took on the order of 5 minutes. I rewrote it in rust and it took on the order of 200m…

> there doesn't exist a problem space where both Rust and Python are reasonable choices This thread, and many other threads about Rust, are filled with people arguing the exact opposite - that Rust is a good, productive language for high-level application development. I agree with you, there's relatively little overlap - that's what I'm arguing for!

Both qualify for writing tiny web servers, cli/byte-manipulation scripts, server automation jobs, in-house GUI applications, and other small stuff. Could technically argue that these are a "relatively little overlap" depending on what you do though..

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#559

Earlier quoted context omitted.

The performance overhead of threads is largely unrelated to how many you have. The thing being minimized with async code is the rate at which you switch between them, because those context switches are expensive. On modern systems there are many common cases where the CPU time required to do the work between a pair of potentially blocking calls is much less than the CPU time required to yield when a blocking call occ…

The cost of context switching in "async" code is very rarely smaller than the cost of switching OS threads. (Exception is when you'ree using a GC language with some sort of global lock.) "Async" in native code is cargo cult, unless you're trying to run on bare metal without OS support.

The cost of switching goroutines, rust Futures, Zig async Frames, or fibers/userspace-tasks in general is on the other of a few nano-seconds whereas it's in the micro-second range for OS threads. This allows you to spawn tons of tasks and have them all communicate with each other very quickly (write to queue; push receiver to scheduler runqueue; switch out sender; switch to receiver) whereas doing so with OS threads would never scale (write to queue; syscall to wake receiver; syscall to switch out sender). Any highly concurrent application (think games, simulations, net services) uses userspace/custom task scheduling for similar reasons.

Re: Maybe Rust isn’t a good tool for massively concurrent, userspace software

#560

Earlier quoted context omitted.

> Rust considered using those (and, at first, that was the project's direction). Ultimately, they went to the stackless operation model because stackfull coroutine requires a runtime that preempts coroutines (to do essentially what the kernel does with threads). This was deemed too expensive. Stackful coroutines don't require a preemptive runtime. I certainly hope that we didn't end up with colored functions in Rust…

They often implement soft preemption. Tokio and others like Glommio do. Usually, it's based on interrupts. The runtime schedules a timer to fire an interrupt, and some code is injected into the interrupt handler. This is used to keep track of task runtime quotas so they can yield as soon as possible afterward. This is the same technique used in Go and many others for preemption. If you don't add this, futures that do…

Tokio and glommio using interrupts is ironically another misconception. They're cooperatively scheduled so yes, a misbehaving blocking task can stall the scheduler. They can't really interrupt an arbitrary stackless coroutine like a Future due to having nowhere to store the OS thread context in a way that can be resumed (Each thread has its own stack, but now it's stackful with all the concerns of sizing and growing. Or you copy the stack to the task but now have somehow to fixup stack pointers in places the runtime is unaware).

https://tokio.rs/blog/2020-04-preemption#a-note-on-blocking

> Tokio does not, and will not attempt to detect blocking tasks and automatically compensate

Post reply on HN