Live data from Hacker News

Rust without the async (hard) part

lunatic.solutions

81–90 of 136 posts

Re: Rust without the async (hard) part

#81
> The problem is that threads just don’t work in practice for massive concurrency.

That's an assumption that is repeated very often recently, and measured very rarely. Truth is that they amount of applications for which they don't work is surprisingly low. I'm working at a well known cloud provider, and lots of people would really be suprised which applications at largest scale are working fine with a thread-per-request model. 50k OS threads are not really an issue on modern server hardware. While it might not be the most efficient [1], it will not perform so bad that it causes an availaiblity impact either.

There's obviously some exceptions to that [2] - but I encourage people to measure instead of making assumptions. Unless one finds themselves in a weekly meeting about server efficiency or scaling cliffs both models probably work.

[1] it really depends on the workload, but people might find an efficiency degradation (e.g. measured as BYTES_TRANSFERRED/CPU_CORES_USED) of 20% at a concurrency level of 1000, or maybe only at a concurrency level of 10k. Coarse-grained work items (e.g. send a large file to a socket) will show a lower degradation.

[2] Load balancers, CDN services, and e.g. chat applications which maintain a massive amount of mostly idle client connections can be such environments. They have a high amount of concurrency that needs to be managed, but less so of "active concurrency". If all clients would be active at the same time, those environments would run out of disk IO or network bandwidth far before CPU or memory become an issue.

Re: Rust without the async (hard) part

#82
post #78
post #73

Earlier quoted context omitted.

Does it matter? The point is that Go has excellent throughput and latency, while using only a single concurrency model.

Yes, it does matter. It has excellent throughput and latency for certain classes of systems, while others are impossible to build. Rust may not impose this constraint while meeting its goals.

Seems like Rust is better in every way right? I can't help but wonder why is it that Go is so much more popular when it comes to language of choice for networked and multi-threaded applications.

Re: Rust without the async (hard) part

#83
post #47

Earlier quoted context omitted.

> it offers much better scaling and performance Myth. Performance won't be better. Scaling arguably is better, but usually the use-case doesn't require the level of scaling where async is superior to OS threads.

I suspect you might be arguing semantics but in practice for certain types of applications performance will in all likelihood offer better performance. Scale and performance are linked when scaling up when you start to hit limits async can make it easier to get more out of your compute than otherwise which is a performance consideration. Calling his statement a myth ignores the context it was made in.

The point of the parent was that better performance is not guaranteed, and it's totally true.

E.g. go ahead and implement a RPC server which e.g. only has to deal with 10 concurrent requests - then measure latencies. The synchronous version might be faster, due to not requiring any epoll calls. The different might get even bigger if e.g. the server is serving static files, and you are measuring throughput - the synchronous version will likely provide higher performance since no extra context-switch from the async-runtime-of-your-choice to threadpool-for-file-io thread and back is required.

You are also right in that once one moves beyond a certain scale the async version might offer better performance. But the scale that is required would be different per application, and not every application requires the scale.

Re: Rust without the async (hard) part

#84

> The problem is that threads just don’t work in practice for massive concurrency. That's an assumption that is repeated very often recently, and measured very rarely. Truth is that they amount of applications for which they don't work is surprisingly low. I'm working at a well known cloud provider, and lots of people would really be suprised which applications at largest scale are working fine with a thread-per-requ…

Once one go with cultish following of async everything idea, measuring things would be heresy.

Re: Rust without the async (hard) part

#85

What does "stream.write_all(&number_as_bytes).unwrap();" do if the socket buffer is full? Does it block this virtual thread running this function? Or does the stream keep buffering? or is it sending the message to some other process which is accumulating those messages. What if I don't wait this thread to block and instead do something else? I believe all of these are handled. I just cannot find sufficient documentat…

Same as the synchronous version: It will block until more data can be written, and then go on and write as much as possible using another async .write() call. It's the same as:

    let mut offset = 0;
    while offset != number_as_bytes.length() {
        let written = stream.write(&number_as_bytes[offset..]).await.unwrap();
        offset += written;
    }
The synchronous version would be the same without the .await, and offers stronger guarantees that either all bytes are written to the socket or the socket errored and is dead. The async version could be cancelled in the middle of the invocation after some segments have already been written.

Re: Rust without the async (hard) part

#86
post #82
post #78

Earlier quoted context omitted.

Yes, it does matter. It has excellent throughput and latency for certain classes of systems, while others are impossible to build. Rust may not impose this constraint while meeting its goals.

Seems like Rust is better in every way right? I can't help but wonder why is it that Go is so much more popular when it comes to language of choice for networked and multi-threaded applications.

Because it's easy to learn and "good enough". Rust is not easy to learn.

Re: Rust without the async (hard) part

#87
post #47

Earlier quoted context omitted.

> it offers much better scaling and performance Myth. Performance won't be better. Scaling arguably is better, but usually the use-case doesn't require the level of scaling where async is superior to OS threads.

I suspect you might be arguing semantics but in practice for certain types of applications performance will in all likelihood offer better performance. Scale and performance are linked when scaling up when you start to hit limits async can make it easier to get more out of your compute than otherwise which is a performance consideration. Calling his statement a myth ignores the context it was made in.

You will absolutely get "more" performance out of async. I'm not sure I could call it much more. It's hard to get an exact number because there isn't exactly a whole lot of pairs of "async" vs "greenthreaded" options out there, but I'd guess you're looking at 20%-30% tops. For most people, and even most people writing async code, this is irrelevant. They are never going to write code that absolutely needs that last 20-30% and that alone is the difference between the problem being solved and not solved.

It certainly isn't like you use a green thread model and you unconditionally throw away a 5x performance factor or something.

There are absolutely cases where that does matter. To name just one, a game engine would not want to throw away that level of performance out of the box. (That's the game engine user's job, to "spend" the quality of the game engine on their task.) But I think there's a lot more programmers who have, without analysis, assumed they're in that class and made a lot of decisions based on that, when in fact they are plural orders of magnitude away from it. To pick a number out thin air, 4 full CPU cores running Rust code that someone has at least glanced at and spent a bit of time optimizing is a loooooot of power.

(The closest current comparison is Rust vs. Go, but Rust works much harder at compile-time optimization and doesn't have GC, and I expect those two things account for the majority of the delta between them, with Go being greenthreaded being non-trivial, but in the clear minority. Stay tuned for Java with Project Loom versus Rust, which has its own rather major differences but will at least be another relevant data point.)

Re: Rust without the async (hard) part

#88
post #55

Earlier quoted context omitted.

Yes. I've been saying this for some time. I call it "async contamination". The async model assumes you spend most of your time waiting for your slow users to do something. (Why a web site, which is inherently stateless, should be doing that routinely is another issue.) I'm writing a metaverse client that has about 10-20 threads, many of them compute bound, running at different priorities. Works fine, but is totally d…

Sorry, offtopic, but what do you mean by "metaverse client"? I've seen you mention this in a couple comments now and I'm intrigued. I don't imagine you mean something to do with Facebook, right?

A metaverse client is the program you run on your machine to talk to a metaverse server. There are several clients for Second Life, a client for VRchat, a client for SineSpace, and so forth. There are web-based clients running in a web browser in WebAssembly, such as the one for Decentraland. All of these are 3D graphics programs.

They're halfway between MMO game clients and web browsers. They have to do most of the things a game client does, but they don't have built-in assets or game logic. Rather than a giant download at install (the biggest AAA titles have passed 100GB), all content is coming from the servers as needed, as with a web browser. The client's job is to present a good-looking 3D world while busily downloading content as the user moves round the world. Hopefully before the user gets close enough to see it in detail. So they have the performance problems of a 3D game with the content-handling problems of a web browser.

An existing open source metaverse client is Firestorm, a viewer for Second Life and Open Simulator.[1] Here's the source code.[2] It's mostly single-thread and OpenGL based. I've made some small contributions to that.

I am working on a replacement, in Rust, with more concurrency. About 20-30 threads, not thousands. Thread priority matters. Top priority is refresh, keeping the frame rate up. Next is servicing the network and user inputs. Then comes content decompression and preprocessing for adding to the scene. Much of this is compute-bound. Rust is a huge help in keeping the concurrency straight. This would be a much harder job in C++.

As the metaverse moves from hype to implementation, this will be a bigger area of activity. Right now, it's a niche.

[1] https://www.firestormviewer.org/

[2] https://vcs.firestormviewer.org/phoenix-firestorm

Re: Rust without the async (hard) part

#89

> The problem is that threads just don’t work in practice for massive concurrency. That's an assumption that is repeated very often recently, and measured very rarely. Truth is that they amount of applications for which they don't work is surprisingly low. I'm working at a well known cloud provider, and lots of people would really be suprised which applications at largest scale are working fine with a thread-per-requ…

> While it might not be the most efficient, it will not perform so bad that it causes an availaiblity impact either.

Performance is important, but the biggest performance gain happens when a program goes from not working to working correctly.

Debugging is another corner case which async makes it intolerably hard to get backtrace and make sense out of what is going on.

It's not like debugging threads is easy, but in a low contention environment which is entirely "1 thread holds state of one request" and there are few interlocking threads in it, threading is a fair bit better than async execution. Plus the logs which indicate thread-names make it possible to draw out something like a post-processed Catapult timing diagram (open chrome://tracing and look at an example, it is a great UI for dropping in your own multi-threaded event log as JSON).

I'm a big fan of executor thread-groups and work queues, but damn does it make hard to mentally walk through a bug when the stack traces are scattered across multiple places.

Re: Rust without the async (hard) part

#90
post #69
post #63

Earlier quoted context omitted.

There is a ton of overlap with every general purpose programming language. So it's correct to say you can solve the vast majority of problems with the majority of programming languages, but languages differentiate themselves in many different ways. One of the main differences between rust and go is that go is a garbage collected language. That feature alone typically creates a large divide in what languages are tryin…

I feel like you’re ignoring my point. The GC prevents Go from competing with Rust on some use cases. But that still leaves a lot of overlap of potential use cases and if your work falls in that region of use cases, you get to pick between the two languages (and a bunch of others too).

I feel like I covered the fact that there's a large overlap between most languages, but to clarify more - when a software team chooses a language they aren't choosing a language based on the overlap, they are choosing it based on the language specific features they think will benefit them the most across the problems they most often try to solve. Go and rusts unique features do no compete with each other like rust/c++ would or like go/elixir (which I feel these two languages are much more comparable in the problems they focus on solving.

Go generally targets small microservices and can be quite limiting (imho) to larger projects because the language semantics are extremely simple and are not geared towards projects with numerous business domains.

Rust on the other hand has extremely powerful generics which enable sophisticated code sharing and composition to enable large projects. Rust also very purposefully targets embedded systems and low level systems programming. You can do these things in go, but it is not something the language is designed to do as a first class priority.

Post reply on HN