I was first exposed to this in the Principles of Reactive Programming Coursera course taught be Odersky and others. At the time, I didn't fully get async, because it was kind of thrown at us with a bunch of other primitives for asynchronous programming.
However, I recently looked into it again for a project I'm on. We decided to convert from `for...yield` comprehensions to `async`/`await`, and I'm very satisfied so far. The former approach wasn't so bad in cases where we just needed to wait on a bunch of unrelated or loosely related future-returning API calls. But it was a mess when some API calls relied on complex logic fed by the results of other API calls. That's when the ability of Scala Async to let you write nearly the same control flow as synchronous code really pays dividends.
It's pretty slick -- it basically transforms your code into a finite state machine, with the states transitions happen as futures resolve. There seems to still be some ongoing work to support the maximum possible number of control flows, but what works now is already pretty useful.
One thing to note is that by default, different async sections will run concurrently. I'm not sure how to change this, but it's something to be aware of if you have any shared mutable state. I had some unsynchronized memoization code fail under a race condition due to this, because the code I converted had used futures on a single thread.
1 comment
[ 3.4 ms ] story [ 10.3 ms ] threadHowever, I recently looked into it again for a project I'm on. We decided to convert from `for...yield` comprehensions to `async`/`await`, and I'm very satisfied so far. The former approach wasn't so bad in cases where we just needed to wait on a bunch of unrelated or loosely related future-returning API calls. But it was a mess when some API calls relied on complex logic fed by the results of other API calls. That's when the ability of Scala Async to let you write nearly the same control flow as synchronous code really pays dividends.
It's pretty slick -- it basically transforms your code into a finite state machine, with the states transitions happen as futures resolve. There seems to still be some ongoing work to support the maximum possible number of control flows, but what works now is already pretty useful.
One thing to note is that by default, different async sections will run concurrently. I'm not sure how to change this, but it's something to be aware of if you have any shared mutable state. I had some unsynchronized memoization code fail under a race condition due to this, because the code I converted had used futures on a single thread.