Hacker News new | ask | show | jobs
by SuperFluffy 1483 days ago
You can spin up a single threaded runtime to perform these async calls without the need to "infect" the rest of the program.

The strategy is to spin up a single threaded async runtime and to just perform that call and block on the runtime itself. The easiest way to do that is probably https://github.com/zesterer/pollster

And there really isn't much in there so you didn't need to worry about performance or anything like that.

I recently refactored a colleague's program from async to sync because it's essentially and entirely sequential.

The reason it started its life as async was the reqwest library, which first and foremost provides async methods to perform http requests.

However, tucked away behind a feature flag aptly named `blocking` there is a small API that wraps the async api and allows making sync/blocking calls in a non-async main. And there they employ the same strategy of having a thin async runtime that blocks on completion of the async call.

3 comments

A multithreaded runtime that is shared for all functions in the app - that other synchronous code then "blocks_on" - will also work. Or e.g. having a cached thread_local tokio runtime.

Btw:

> And there really isn't much in there so you didn't need to worry about performance or anything like that.

Actually you have to! In case you write a program that spawns background threads (with whatever async runtime), and then let your foreground thread interact with that - it will have performance implications since your program now does additional context switches. It might or might not matter for your application, but in general it's rather easy to lose all perf benefits that async code actually might provide by still requiring switches between full threads.

This works with runtime agnostic futures, but you can't do any I/O without requiring a specific runtime. reqwest for example doesn't use a generic block_on, it runs tokio behind the scenes.
You can spawn a simple Tokio I/O runtime with Builder::new_current_thread().with_io().build().

The catch is that it’s not really “simple”, and idk the performance penalty.

I tried things like pollster, and they wouldn't work in my case for reasons I can't remember (but I asked for assistance on the Rust Discord and there didn't seem to be ways around it).