4 ms·
> low resource usage of async/await Will calling a coroutine do zero heap allocations like async in Rust? > with the ease-of-use experience of threads That's
by pkolaczk 4y ago
> low resource usage of async/await
Will calling a coroutine do zero heap allocations like async in Rust?
> with the ease-of-use experience of threads
That's highly subjective. Threads usually require locking which is often hard to get performant and correct at the same time. Async/await allows to write concurrent code with no synchronization.
- mike_hearn 4y ago> Async/await allows to write concurrent code with no synchronization Well you still need some sort of synchronization, because an "await" allows arbitrary other actions to occur. If an await is introduced in code you transitively call then you might find that some invariant you were expecting to hold has now changed across a call when it previously didn't. Fundamentally, locks are about making invariants atomic and that's independent of exactly how code is scheduled and when.
- jayd16 4y agoThis is impossible because of *gasp function coloring. You can't just make a sync function async without dealing with the fallout explicitly in c#.
- mike_hearn 4y agoYou can make an async function contain an await at more places than it previously had. When writing code in colored languages your code tends towards lots of stuff being marked async, so more 'await' points being introduced can change behavior.
- jayd16 4y agoYou're saying something is bad because it could affect a race condition you had? Doesn't everything fall under that issue? That's not changing from invariant to variant.
- mike_hearn 4y agoI'm not saying it's bad, I'm saying that you can still have races and thus still need some form of synchronization even when using async/await. Whilst in simple cases you can preserve invariants just by carefully choosing where an await is done, as things get more complex you constantly run the risk that someone will introduce another await somewhere else (and maybe more async marked functions to enable that), without understanding that the 'await' can now run code that violates some invariants. Locks and other such mechanisms let you mark certain code as executing atomically regardless of scheduling.
- matsemann 4y ago> Async/await allows to write concurrent code with no synchronization. Hmm,I don't see how async/awaits makes a difference. Care to explain? Like, if you have multiple sources that can add or read from a queue, unless there is a single thread running all your async loops (ala python), you still need some synchronization. At least that's my experience using coroutines heavily in kotlin.
- jayd16 4y agoThe synchronization is handled by the runtime. While you could still have concurrent access issues, async tasks will not deadlock in c#, unlike lock mechanisms. You don't get concurrency for free, but the finer details of lock management are avoided.
- pkolaczk 4y agoI'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.
- deleted 4y ago[deleted]