3 ms·
In the words of Steve Jobs, “you’re holding it wrong”. I’m guessing your code is blocking. You absolutely cannot do blocking code in async in any language, unl
by andrewstuart 3y ago
In the words of Steve Jobs, “you’re holding it wrong”.
I’m guessing your code is blocking. You absolutely cannot do blocking code in async in any language, unless the blocking is super quick. No blocking io.
async code should yield great performance if you are doing everything the right way. Yes it is single threaded but either run multiple threads in rust or run multiple instances of your program with systemd.
That applies same to rust, Python, javascript, any async language.
I wrote a prototype message queue in Rust with Actix and got 7 million messages per second via http.
- bad_user 3y agoJava, C#, probably Go and others, are able to do async I/O on multiple threads. It doesn't help with the actual async I/O being performed, but it does help with parallelising CPU work, or with the fact that not all I/O can be async and the runtime is faking it, such as local file I/O, which is going to be blocking system threads. Async I/O is all about multiplexing work on few CPU cores efficiently, and multi-threading is still required. Python or JavaScript are seriously limiting environments and should not be given as an example when we're talking about a language that does 1:1 scheduling.
- andrewstuart 3y agoI don’t really get your point. You cannot, (should not), do blocking IO in async in any language. The language provides libraries to do non blocking IO. What is unclear about that? Multi threading has nothing to do with async, except as a way to run certain things in an executor thread to avoid blocking. Also I don’t really know what you mean by async IO…. even in the languages you reference I would guess IO operations are all run in a single thread.
- bad_user 3y ago> You cannot, (should not), do blocking IO in async in any language. On platforms with 1:1 scheduling, of course you can. Blocking I/O executed on another thread, with a callback to execute when done, becomes async I/O (from the user's PoV). Ofc, when we talk about async I/O, we also refer to the kernel APIs being used, such as select/poll/epoll/io_uring. Say, working with Epoll is usually done via a single-threaded "event loop", but that only listens for the operations possible for an open file/socket. The read/write operations are still potentially blocking, so for efficiency you need multiple threads. The dirty secret is that async I/O, as implemented by Linux, isn't actually fully async.
- BatmanAoD 3y agoThat's...not...how threads or async work...? > Blocking I/O executed on another thread, with a callback to execute when done, becomes async I/O (from the user's PoV). That's not what we're talking about when we discuss languages with async I/O, though. That's just bog-standard synchronous I/O with multithreading. > The read/write operations are still potentially blocking, so for efficiency you need multiple threads. That doesn't actually follow. The entire point of language-level async I/O is to be able to continue doing other work while waiting for the kernel to finish an I/O operation, without spawning a new OS thread just for this purpose.
- mplanchard 3y agoTokio's default scheduler is multi-threaded, and Rust does this very well. You just have to be explicit when you want to run some non-async blocking code in a way that won't block a thread.
- sargun 3y agoRight, I think async is bad. We have threads, and operating system level isolation with processes. For the most part, these primitives work fine. My code wasn't blocking, but it did a very small amount of computation, locked on what was typically a highly contended (async) lock, and then dispatched a bunch of blocking I/O operations. Each of these turned into a context switch under the hood. There were parts of my code that were computer intensive, but determining that without being able to use my normal tools was a pain, and I had to come up with heuristics of whether or not to dispatch with spawn_blocking, since the call had significant overhead. An abstraction that was meant to simplify program resulted in me spending a lot more time staring at it. I think one difference with Python is that the async implementation doesn't try to hide or abstract I/O away from you. If you're doing I/O, you know you're going to block, and thus you're forced to acknowledge it by spawning it on another thread.