5 ms·
I'm talking from perspective of Rust's async/await implementation, I'm not sure if the same holds for other languages with async like C# or Kotlin. Nevertheless
by pkolaczk 4y ago
I'm talking from perspective of Rust's async/await implementation, I'm not sure if the same holds for other languages with async like C# or Kotlin. Nevertheless I can do a loop like this:
let mut buffer = ... // create buffer for holding data
let mut input: TcpStream = ... // connect to remote endpoint
let mut output: TcpStream = ... // connect to remote endpoint
loop {
select! {
_ = input.readable() => {
input.try_read(&mut buffer)?;
}
_ = output.writable(), if !buffer.is_empty() {
output.try_write(&mut buffer)?;
}
}
}
The mutable buffer is shared between the part that reads from input and the part that writes to output, and reads/writes happen concurrently and independently. Yet there is no explicit locking anywhere!
Synchronization is achieved implicitly by the fact that sequential code executes in only one place at once, so when it executes the reading branch, it does not execute the writing branch. You can apply exactly same reasoning as with any single-threaded, sequential code.
You cannot model this easily with threads. If it was a single thread with blocking I/O, then it could block forever in one branch and stop reacting to events on other branches. If it were multiple threads, then they would somehow need to synchronize accesses explicitly to the shared buffer.