Live data from Hacker News

Tokio 1.0 – async runtime for Rust

tokio.rs

141–150 of 422 posts

Re: Tokio 1.0 – async runtime for Rust

#142
post #126

Earlier quoted context omitted.

> Considering a normal-sized Linux server can handle a million threads without much trouble, it really seems like misplaced effort Seems like that would use a lot of memory for all the stacks

Based on this, the default value is 2MB: https://unix.stackexchange.com/questions/127602/default-stac... So that would mean a lot of memory for 1 million threads, 2TB of RAM. But you can change the default. With a 64k stack you'd use up ~68GB of RAM, which doesn't seem like a lot for 1 million threads and 1 million requests happening at the same time.

That is also the maximum stack size which shouldn't normally be reached. You'll have to be careful how you use memory when you're handling a million clients, either as async or threaded.

Re: Tokio 1.0 – async runtime for Rust

#143

It is unfortunate, that libraries have to be coded against specific runtime and not generically. There is tokio and there is smol (likely discontinued, since author left rust), maybe other runtimes will emerge, but whole ecosystem is already tied to tokio.

Since when did Stjepang leave Rust?

He switched to Go.

Stjepang is a very smart person and I'm actually quite excited about what he's going to bring to the Go world.

Re: Tokio 1.0 – async runtime for Rust

#144
post #126

Earlier quoted context omitted.

Based on this, the default value is 2MB: https://unix.stackexchange.com/questions/127602/default-stac... So that would mean a lot of memory for 1 million threads, 2TB of RAM. But you can change the default. With a 64k stack you'd use up ~68GB of RAM, which doesn't seem like a lot for 1 million threads and 1 million requests happening at the same time.

What "normal-sized Linux server" has 70GB of RAM?

One that wants to handle a million requests per second?

Or would you want to do that with a Raspberry Pi? :-)

> What "normal-sized Linux server" has 70GB of RAM?

Also, why are you "quoting" what I did not say?

Re: Tokio 1.0 – async runtime for Rust

#145
post #140
post #96

Earlier quoted context omitted.

Synchronous code is even easier to reason about than code using async syntax sugar.

No, multithreaded synchronous code is not easier to reason about than async. I think most would agree.

I disagree, at least in Rust. async is hard. Threading is easy.

Re: Tokio 1.0 – async runtime for Rust

#146
post #77

I don't really get these modern async APIs. In languages like Javascript I thought they only made sense because JS interpreters are (historically) single-threaded, so you really have no choice but async to express some concepts. Fine. But in Rust you can just spawn threads, share data through channels or mutexes, use OS-provided async IO primitives to poll file descriptors and do event-driven programming etc... I tri…

I had the same thing initially.

The upside of async over a simple event loop is, in my experience, when things become less simple, and you end up with hard-to-read little state machines all over the place.

With async, you can have your event loop, but the state machines are handled by the compiler. Code is like threaded code. That can be very convenient.

Threads, obviously, accomplish the same thing, and arguably more easily. But threads have a performance problem when they must interact heavily. Cross-thread communication is expensive. Single-threaded async task interaction is very cheap, comparatively (I use tokio only in single-threaded mode, as an event loop replacement; its multi-threaded scheduler performs terribly on serious I/O). I think the interaction problem is often more important than just the number of tasks.

As for the function coloring argument, I've started to see the async keyword as documentation. A non-async function is "regular logic", it must complete without blocking. An async function is a state machine; as such it must be part of a larger state machine (the event loop), and it can go down into smaller sub-state machines (i.e. call other async functions). If you make that distinction explicit, it all makes a lot of sense.

Re: Tokio 1.0 – async runtime for Rust

#147
post #77

I don't really get these modern async APIs. In languages like Javascript I thought they only made sense because JS interpreters are (historically) single-threaded, so you really have no choice but async to express some concepts. Fine. But in Rust you can just spawn threads, share data through channels or mutexes, use OS-provided async IO primitives to poll file descriptors and do event-driven programming etc... I tri…

How many threads can you spawn before the system grinds to a halt? If you're processing thousands of requests per second and each request gets its own thread then you will start to queue on thread spawning. Don't forget that each thread gets its own stack taking up megabytes of memory.

The async concept has been used for decades in pretty much every product I've worked on professionally, from enterprise raid controllers to network protocol implementations and telephony software. An engineer I respect once told me that really it's the only way to write services at scale, and anything else is just a step on the road until you reinvent it. He was probably exaggerating, but it is very important, and nearly ubiquitous.

Having used custom frameworks for async code in C and C++, it's really refreshing to have it baked into the language and well supported. It's yet another arrow in Rust's fantastic quiver.

Re: Tokio 1.0 – async runtime for Rust

#148
post #126

Earlier quoted context omitted.

Based on this, the default value is 2MB: https://unix.stackexchange.com/questions/127602/default-stac... So that would mean a lot of memory for 1 million threads, 2TB of RAM. But you can change the default. With a 64k stack you'd use up ~68GB of RAM, which doesn't seem like a lot for 1 million threads and 1 million requests happening at the same time.

What "normal-sized Linux server" has 70GB of RAM?

Most servers support at least 128GB; it isn't even very expensive. And if you want to handle a million concurrent users you also need to consider CPU and latency, so for most real-world workloads the memory probably won't even be your bottleneck.

Re: Tokio 1.0 – async runtime for Rust

#149

Earlier quoted context omitted.

When learning Rust a few months ago, I built a small client library for a REST API using reqwest (which uses Tokio). I then started writing a web app using Tide ( https://github.com/http-rs/tide ). I eventually realized that it would be difficult to use the library I had built earlier since Tide uses the async-std runtime rather than Tokio. That was very disappointing. Is there any plan to make it easier to write "ru…

that's a good point, when playing a bit with rust last year I found that the libraries that deal with "async stuff" (like http clients, db clients etc) are mostly split, some use tokio and some use async-std, and they were incompatible. Not sure if the situation has improved now but it looked like an ecosystem split at the time.

Work is in progress, but the situation hasn't improved yet for end users.

Re: Tokio 1.0 – async runtime for Rust

#150

Earlier quoted context omitted.

> One is they make your functions colored This is definitely a good thing. All computations should me "marked" as total or effectful with various possible effects (blocking, async, nondeterministic, possibly non-terminating etc etc). Reasoning about your program is hard when each computation is a blackbox possibly containing any side-effects which could cause unpredictable changes in the control flow and result in a…

> This is definitely a good thing. All computations should me "marked" as total or effectful with various possible effects (blocking, async, nondeterministic, possibly non-terminating etc etc). Marking functions for side-effects would be a good thing but it isn't what function coloring means in this context. An async function and a normal function are semantically the same, they just have different syntaxes and you c…

Yes, the standard library has a bunch of legacy blocking IO stuff. But in general, most modern libraries tend to stick to a convention of:

- async (or explicitly Future/Stream): external effects (I/O, interacts with synchronization, whatever)

- &mut: local effects

- otherwise: pure

Post reply on HN