Live data from Hacker News

Async-std: an async port of the Rust standard library

async.rs

161–170 of 238 posts

Re: Async-std: an async port of the Rust standard library

#161

Earlier quoted context omitted.

> that would have been hard to do 5 years ago. Five years ago Rust still had green threads. Literally every standard library I/O function was async, and the awaits were always written for you with no effort. Its literally taken five years to get back to an alpha thats not as good, and we'll still have to wait for a new ecosystem to built on top of it. I know not everyone writes socket servers and so forcing the old m…

> Its literally taken five years to get back to an alpha thats not as good The new I/O system is better in several ways. First, as you acknowledged, not everyone writes servers that need high scalability. M:N has no benefit for those users, and it severely complicates FFI. Second, async is faster than M:N because it compiles to a state machine: you don't have a bunch of big stacks around.

I don't think M:N forces a stack. The stack no stack is called stackless coroutine vs stackful coroutine.

M:N is the parallelization level. I'm actually not sure if Rust is M:1 or M:N or both based on configuration.

M is the number of concurrent process in the language, basically the number of user thread. These user threads can be implemented to be stackful or stackless, up to the language. The N is the number of OS threads.

At least that's always been my understanding.

Re: Async-std: an async port of the Rust standard library

#162
post #135

Earlier quoted context omitted.

People are happily running Rust servers in production using thousands of concurrent threads per second.

Thousands isn't much.

You can scale up to tens of thousands of threads. But if that isn't enough for your application, then you can use async!

M:N threading was slower than 1:1 in Rust.

Re: Async-std: an async port of the Rust standard library

#163

Earlier quoted context omitted.

Any code in Rust is free to bind to FFI and sockets can be gained through `libc`.

I didn't literally mean "How is that possible?" I meant: is that a real thing? Is there a database binding out on crates.io that uses no_std ?

SQLite is C code and any Rust usage of it will not play nicely with M:N. This is just off the top of my head. I'm sure there are plenty of other examples.

Re: Async-std: an async port of the Rust standard library

#164
post #9

Earlier quoted context omitted.

Are those really the only options? I'm trying to wrap my head around how using a fixed size thread pool for I/O automatically implies deadlocks but I just can't. Unless the threads block on completion until their results are consumed instead of just notifying and then taking the next task.. I can definitely imagine blocking happening while waiting for a worker to be available, though. Did you mean simply blocking ins…

N threads, with N readers waiting for a message that will only come if the N+1 reader (still in the queue) gets a message first.

But sure one must use an output queue, not synchronously wait for the consumer to consume a result?

Re: Async-std: an async port of the Rust standard library

#165

Earlier quoted context omitted.

io_uring grew support for buffered IO in recent kernels, so we should have widespread support for this in userspace circa 2025

Or just detect it and swap out the implementation. Less than a year until an Ubuntu LTS that has it.

I should have written 2035 to make the sarcasm a little clearer :)

Re: Async-std: an async port of the Rust standard library

#166
post #60

Earlier quoted context omitted.

AFAIK Windows handles truly asynchronous buffered IO in some circumstances, but I feel once you're past the point of managing the abstraction or caring about its internal details, it doesn't really matter if there is a tiny chunk of dedicated stack in the kernel, that's a problem for the OS

IOCP uses a pool of quasi-kernel threads (i.e. schedulable entity with a contiguous stack for storing state) with polling, very much like how io_uring and other incarnations of AIO in the Linux kernel work; and for that matter it's not unlike how purely user space AIO implementations work. The benefit of IOCP and io_uring is there's one less buffer copying operation. The biggest benefit of IOCP, really, is that it's…

> OCP uses a pool of quasi-kernel threads

Is there any further documentation for it? I would have expected there doesn't need to be a real stack. Only state-machines for all the IO entities (like sockets) which get advanced whenever an outside event (e.g. interrupt) happens and which then signal the IO completion towards userspace. Didn't expect that it's necessary to keep stacks around.

Re: Async-std: an async port of the Rust standard library

#167

Earlier quoted context omitted.

I think the point is that "colored" functions only existed because Rust did not previously have async support. Now that it has async support, new code can be one color: async, while maintaining ergonomics. Maybe new code will be exclusively async and existing code will switch over.

Not all new code shouldn't be async. I write graphics code. There is no benefit to me, or any of my users, if all of my code is async. No system has 10,000 simultaneous GPUs to drive independently.

I agree with your general point, but I do want to point out (as I'm sure you're aware) there's plenty of asyncronous logic in graphics code.

Some (but not all) of which might even benifit from async... although graphics code has it's own solutions to many of these problems, and it certainly wouldn't be the bread and butter of your core render loop.

1) For performance reasons, your GPU consumes command buffers after a decent delay from when your CPU requests it. This means async logic crops up for screenshot/recording readbacks, visibility queries, etc. assuming you don't want to simply stall everything and tank your framerate.

2) New lower level graphics APIs expose the asyncronous logic of command submission more than ever before, limiting safe CPU access to memory based on what the GPU is still accessing. This sometimes spills into higher level APIs - e.g. bgfx buffer uploads can either take a reference to memory (fast) - which you must keep valid and unmodified for a frame or two (asyncronous, and currently difficult to expose a sound+safe API for to Rust) - or it can make an extra deep copy (perf hit) to pretend it's behaving in a more syncronous fashion.

3) Resource loading is heavily asyncronous. You don't want to stall a game out on blocking disk I/O for a missing minimap icon if you can just fade it in a few seconds later. I might not have 10,000 GPUs to drive, but I've certainly had 10,000 assets to load, semi-independently, often with minimal warning.

Re: Async-std: an async port of the Rust standard library

#168

I must be dumb, because every time I dive into async/await, I feel like I reach an epiphany about how it works, and how to use it. Then a week later I read about it again and totally lost all understanding. What do I gain if I have code like this [0], which has a bunch of `.await?` in sequence? I know .await != join_thread(), but doesn't execution of the current scope of code halt while it waits for the future we are…

Say you want to listen to a socket and also receive input from the keyboard at the same time.

If you have an async method that can wait for input on both devices, you can await the results of both of them, and they won't block eachother.

Re: Async-std: an async port of the Rust standard library

#169
post #109

Earlier quoted context omitted.

async/await are coroutines and continuations (bear with me). Here is synchronous code: result = server.getStuff() print(result) Here is synchronous code, that tries to be asynchronous: server.getStuff(lambda result: print(result)) Once server.getStuff returns, the callback passed to it is called with the result. Here is the same code with async/await: result = await server.getStuff() print(result) Internally, the com…

Thanks. Helpful. My question is, in this example: result = await server.getStuff() second = await server.getMoreStuff(result+1) print(result) `await getStuff()` MUST terminate before `await getMoreStuff() ` begins. So this chunk alone is analagous to synchronous code, unless we're in the middle of a spawned task, and there are other spawned tasks in the executor that can be picked up.

Yes, the idea is that the thread that is executing this piece of code can "steal" other work when it is awaiting on either of those methods.

Frankly, in the case of sequential flow like the above, I would rather write

  result = server.getStuff()
  second = server.getMoreStuff(result+1)
  print(result)
and have the runtime automatically perform work-stealing for me. No need for awaits. They just litter the code. This is what Go does.
Post reply on HN