On Tuesday, 24 October 2017 at 04:26:42 UTC, Adam Wilson wrote:
On 10/23/17 17:27, flamencofantasy wrote:
On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
On 10/23/17 08:21, Kagamin wrote:
[...]
Actually I think it fits perfectly with D, not for reason of
performance, but for reason of flexibility. D is a polyglot
language,
with by far the most number of methodologies supported in a
single
language that I've ever encountered.
[...]
There is a lot of misunderstanding about async/await. It has
nothing to
do with "conservation of thread resources" or trading "raw
performance
for an ability
to handle a truly massive number of simultaneous tasks".
Async/await
is just 'syntactic sugar' where the compiler re-writes your
code into
a state machine around APM (Asynchronous programming model
which was
introduced in .NET 2.0 sometime around 2002 I believe).
That's all
there is to it, it makes your asynchronous code look and feel
synchronous.
The only parts of Async/Await that have anything to do with APM
are the interop stubs. C#'s Async/Await is built around the
Task Asynchronous Programming model (e.g. Task and Task<T>) the
compiler lowers to those, not APM. A common misunderstanding is
that Task/Task<T> is based on APM, it's not, Task uses
fundamentally different code underneath. On Linux/macOS it
actually uses libuv (at the end of the day all of these
programming models are callback based).
I’ll throw in my 2 rubbles.
I actually worked on a VM that has async/await feature built-in
(Dart language).
It is a plain syntax sugar for Future/Promise explicit asynchrony
where async automatically return Future[T] or Observable[T] (the
latter is async stream).
Async function with awaits is then re-written as a single
call-back with a basic state machine, each state corresponds to
the line where you did await.
Example:
async double calculateTax(){
double taxRate = await getTaxRates();
double income = await getIncome();
return taxRate * income;
}
Becomes roughly this (a bit more mechanical though):
Future!double calculateTax(){
int state = 0;
Promise!double __ret;
double taxRate;
double income;
void cb() {
if(state == 0) {
state = 1;
getTaxRates().andThen((double ret){
taxRate = ret;
cb();
});
}
else if (state == 1) {
state = 2;
getIncome().andThen((double ret){
income = ret;
cb();
});
else if (state == 2){
__ret.resolve(taxRate*income);
}
}
cb();
}
It doesn’t matter what mechanics you use to complete promises -
be it IO scheduler a-la libuv or something else. Async/await is
agnostic to that.
Still there is a fair amount of machinery to hide the rewrite
from the user and in particular print stack trace as if it was
normal sequential code.
Yes, C#'s async design does make code look and feel
synchronous, and it was intentionally designed that way, but
that is not *why* they did Async. That misunderstanding arises
from an interview that Anders did in which he was asked why
they held Async back for three years after announcing it at
PDC08. In that same talk Anders specifically says that the
purpose of the Async is to free up threads to continue
execution, his example is a Windows Desktop Message Pump and
fetching pictures from the internet (long-wait IO), but the
principal applies to any thread. They held back async for three
years because they needed to refine the language syntax to
something that people could learn and apply in a reasonable
amount of time. IIRC there is a Channel9 video where Anders
explains the evolution of Async Await.
In other words - explicit asynchrony where a thread immediately
returns with Future[T] and moves on to the next task. It’s just
hidden by Async/Await.