Is async_std always better than std?

I am a novice to Async coding, But I do know that async/threads can hurt rather than help a program's performance if used incorrectly, I would think that Librarys such as Tokio would be good in most situations. But I wanted to know, should I overhaul all of my std code with async_std?

async_std, tokio, and friends are there to do a job. The standard library is also there to do a job, using a different approach. Neither is always better or worse - use the tool that suits the program you're trying to build.

Asynchronous IO can be helpful if you want to multiplex IO-based operations and state machines while being able to describe those state machines using sequential programs. The IO primitives in the stdlib can't do that (though they can be used to build that for yourself, if you want to), but not every problem needs that, either. A purely serial program, using blocking IO, is more than adequate for many problems and a better fit for some than async privitives would be.

3 Likes

Generally blocking uses of async APIs are slower than just using equivalent blocking APIs. Sometimes dramatically so. At best, they require a system call to start the request and another to finish it, but often they also require heap allocation of buffers instead of being able to use the stack, and so on.

This is not a problem for their use case, which is when you are IO bound and trying to keep the CPU busy with a lot of parallel work, eg a server with thousands of current connections. A few hundred extra cycles per operation is a small price for not having to start and continually swap thousands of platform threads.

Also keep in mind async filesystem access in most libraries, including all cross platform rust crates I know of, simply use the blocking APIs delegated to another thread, and are severely slower.

Many years ago a customer had a cell phone router device. A technician plugged serial cable into one of the routers to get a terminal and enabled logging. Later when the technician went for dinner, he closed the laptop. The logging continued until the serial buffer filled up, and because serial port had flow control enabled, I/O blocked on the logging from all threads. After a few seconds the watchdog reset the router because the time critical tasks were not checking in. Due to another bug, the unqualified reset caused all connected routers of the same model to reset as well in domino effect. This caused all the calls for one carrier to drop all across the eastern US, in cyclic manner for several hours.
You should not use async I/O everywhere, it's slow, but there are some places where if you don't use it you can create big problems. :slight_smile:

I'm not sure how async would have saved you there: at best you have a logging framework that drops messages under load, at worst you get whatever your out of memory behavior is as it infinitely buffers, and that's often the least tested, most broken state of a system.

As with any illustrative examples modeled on For Want of a Nail - Wikipedia, in reality there were several design problems, and I chose to focus on the trigger cause, The real time threads that were routing calls would be considered more important, than the accessory information of the diagnostic log messages they optionally produce. So the log messages should be reported asynchronously, and discarded if the buffer fills. Here you need to distinguish between logging and alerts, though many modern systems mix the two. An "alert" can be delivered asynchronously, but needs to be preserved in all cases, so it is acted on eventually or available RCA after system failure.