Taking a timeout — From Go To Rust
From one to the other
The select statement in Go makes it pretty easy to have multiple tasks compete against each other. Which ever channel returns first wins and you get to work with the result. There are many examples of how to do this in Go and all you need is already built in. Figuring out how to do the same in Rust can be more of a puzzle.
Let’s say you want to read some user input from the terminal but timeout if the user takes more than X amount of seconds to do so. It would look something like this in Go.
And now for Rust.
What’s the difference?
If you squint the code doesn’t look that much different. But if you look closer there seems to be some extra hoops to jump through. To create this example, in contrast to Go, we needed to pull in an external library: Tokio.
Rust doesn’t have the equivalent of goroutines built in, which means that we only have native threads as a pre-packaged solution. We can however achieve something similar to goroutines by introducing async/futures into the mix. Since Rust’s async model is based on a polling strategy we need a runtime to “drive” our futures. This is where Tokio comes in.
Tokio is a runtime for executing futures but also includes some nice things, like the delay_for, spawn and unbounded_channel functions.
Piece by piece
go -> spawn
The spawn function will create a new asynchronous task and is our Go equivalent to the go keyword.
time.Sleep -> delay_for
The delay_for will sleep the future in the same way time.Sleep will put our goroutine to sleep.
make (chan …) -> unbounded_channel
Finally, the unbounded_channel function will create a channel, like the one in Go, but within the async runtime of Tokio.
select -> select!
To wrap this up we use Tokio’s built-in select! macro, which will take the first future to run to completion — the rest will be cancelled and dropped.
That’s it :)
The reason for reading stdin in a native thread instead of in a future within the Tokio runtime is due to blocking issues. You can read more about it here.