I am trying to understand asynchronous programming and came across async/await keywords. I got stuck in understanding use of async/await keywords. I actually looked in two programming languages, JavaScript and C# and found much differences in use of async/await keywords in both languages.
For JavaScript it says:
Async/await makes your code look synchronous, and in a way it makes it behave more synchronously. The await keyword blocks execution of all the code that follows it until the promise fulfills, exactly as it would with a synchronous operation.
Link: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await#:~:text=Async%2Fawait%20makes%20your%20code,would%20with%20a%20synchronous%20operation.
So, its saying that async/await will make the execution synchronous.
For C# it says:
The async keyword turns a method into an async method, which allows you to use the await keyword in its body.
When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete.
Link: https://learn.microsoft.com/en-us/dotnet/csharp/async#:~:text=The%20async%20keyword%20turns%20a,used%20inside%20an%20async%20method.
So, its saying that use of async/await will make the code execution asynchronous.
I would like to ask, is there really a difference between the use of async/await keywords in JavaScript and C#?
Or,
Is something missing in above statements?
Javascript docs says 'it makes your code look synchronous', it doesn't say 'it makes your code synchronous'.
In terms of behavior there's no difference between javascript and c# in async/await.
async keyword denotes that there's an asynchronous operation in this method.
await keyword helps making a CPS (continuation passing style) coding into a code that looks like synchronous. CPS is similar to using then() in javascript after promises or using ContinueWith() in C# Tasks.
Any code before 'await' is running synchronously under current thread. When execution reaches to 'await', the awaited operation starts under a new thread (not necessarily a new thread, but suppose a new thread), hence an asynchronous operation starts, and current thread is freed. When the awaited operation ends, execution returns to the point it left off in the 'await' keyword and continues.
The internal working of javascript and C# are different.
Javascript is event-driven. There is a main event loop and a single thread in javascript. When the awaited operation finishes, an event is raised under the hood and the main single thread continues executing of the async function where it was left off.
In C# there's no event loop or a single thread. We either should use manual threads and explicitly wait and join them after they did their job, or we should use something like async/await that manages thread and continuation management on behalf of us. Using TPL which C#'s async/await internally uses that, continuation of an async code is passed to another task using callbacks.
Anyhow, 'await' keywrods turns a complicated chain of nested then() -js- or ContinueWith() - c#- into a simple beautiful code that looks like a normal -synchronous- code.
function doSomethingCPS() {
asyncOperation1()
.then(r1 => { consume(r1); return asyncOperation2() })
.then(r2 => { consume(r2); return asyncOperation3() })
.then(r3 => { consume(r3); })
}
async function doSomethingAsync() {
var r1 = await asyncOperation1();
consume(r1);
var r2 = await asyncOperation2();
consume(r2);
var r3 = await asyncOperation3();
consume(r3);
}
The two codes are equivalent. But, it's clear that the latter is much more simpler and easier to read.
There's a difference between thread management in javascript and c#.
As it is said, in javascript there's only one thread. If it blocks for any reason, the page will block. It's when browsers show 'The page is not responding' or 'There is a javascript code in this page that blocks the page' message after 20-30 seconds.
In HTML5 worker threads were introduced that helps to employ a real separate thread. It's another topic though.
You might ask if there's only one thread in javascript, how on earth can an asynchronous operation work that is said to work under another thread?!
Good question. In javascript although there's only one single thread, there are objects that natively use separate threads. timers - setInterval() and setTimeout()-, XMLHttpObject() and fetch() are good examples in this regard. Thus, in javascript we indeed can have asynchronous code.
One final point is the way C# uses threads. In C#, async/await works using a library named TPL (Task Parallel Library). There is a Task class at the heart of TPL that resembles an asynchronous task.
The real point we should know is that, a Task is equivalent to an async operation, but it does not necessarily mean a Task uses explicitly a separate thread. There's a task scheduler in TPL that controls internal threads usage. If a Task's job is quick, using a separate thread wastes resources, so the task will run under current thread.
The only thing we should know is that a Task is a logical unit of asynchronous code. In fat, Task is introduced to free us of manually thread management which is nearly a low-level code.
Using async/await we are rid of all boilerplate code that are required under the hood to provide asynchronous code. We can focus on our business code instead.
I am not familiar with JavaScript but this statement:
Async/await makes your code look synchronous, and in a way it makes it
behave more synchronously. The await keyword blocks execution of all
the code that follows it until the promise fulfills, exactly as it
would with a synchronous operation.
Sounds pretty much applicable to C# async/await. For both cases your code looks like you execute it synchronously and your execution is sequential. Because in C# when you have code like this:
// ...
await FooAsync();
Console.WriteLine("Await has returned the execution");
It seems as if your execution thread were running FooAsync, and then, the same thread is calling Console.WriteLine. Whereas in reality when the execution thread hits await, it does lots of things behind the scene. Here's a good article about it. But in most of the cases,
When the await keyword is applied, it suspends the calling method and
yields control back to its caller until the awaited task is complete.
The thread that were executing your code will go about his business. And then proceed with Console.WriteLine when FooAsync is complete by another (or the same) thread.
This behavior is enormously helpful when you work with UI threads like in WPF or WinForms applications.
For example, FooAsync is a very heavy method. It does lots of calculations and takes a lot of time to complete. But you're running your code on UI and when a user hits a button, the underlying code is executed by the UI thread. So if you'll be running and waiting FooAsync synchronously like this:
FooAsync().Result;
Your UI would be "freezed" and the user would demise you.
So when you go
await FooAsync();
UI thread "asks" TaskScheduler to run FooAsync by whatever available thread. After the Task is completed, TaskScheduler tries to execute next line:
Console.WriteLine("Await has returned the execution");
by the UI thread again,
exactly as it would with a synchronous operation.
Related
I thought that they were basically the same thing — writing programs that split tasks between processors (on machines that have 2+ processors). Then I'm reading this, which says:
Async methods are intended to be non-blocking operations. An await
expression in an async method doesn’t block the current thread while
the awaited task is running. Instead, the expression signs up the rest
of the method as a continuation and returns control to the caller of
the async method.
The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the
method is active. You can use Task.Run to move CPU-bound work to a
background thread, but a background thread doesn't help with a process
that's just waiting for results to become available.
and I'm wondering whether someone can translate that to English for me. It seems to draw a distinction between asynchronicity (is that a word?) and threading and imply that you can have a program that has asynchronous tasks but no multithreading.
Now I understand the idea of asynchronous tasks such as the example on pg. 467 of Jon Skeet's C# In Depth, Third Edition
async void DisplayWebsiteLength ( object sender, EventArgs e )
{
label.Text = "Fetching ...";
using ( HttpClient client = new HttpClient() )
{
Task<string> task = client.GetStringAsync("http://csharpindepth.com");
string text = await task;
label.Text = text.Length.ToString();
}
}
The async keyword means "This function, whenever it is called, will not be called in a context in which its completion is required for everything after its call to be called."
In other words, writing it in the middle of some task
int x = 5;
DisplayWebsiteLength();
double y = Math.Pow((double)x,2000.0);
, since DisplayWebsiteLength() has nothing to do with x or y, will cause DisplayWebsiteLength() to be executed "in the background", like
processor 1 | processor 2
-------------------------------------------------------------------
int x = 5; | DisplayWebsiteLength()
double y = Math.Pow((double)x,2000.0); |
Obviously that's a stupid example, but am I correct or am I totally confused or what?
(Also, I'm confused about why sender and e aren't ever used in the body of the above function.)
Your misunderstanding is extremely common. Many people are taught that multithreading and asynchrony are the same thing, but they are not.
An analogy usually helps. You are cooking in a restaurant. An order comes in for eggs and toast.
Synchronous: you cook the eggs, then you cook the toast.
Asynchronous, single threaded: you start the eggs cooking and set a timer. You start the toast cooking, and set a timer. While they are both cooking, you clean the kitchen. When the timers go off you take the eggs off the heat and the toast out of the toaster and serve them.
Asynchronous, multithreaded: you hire two more cooks, one to cook eggs and one to cook toast. Now you have the problem of coordinating the cooks so that they do not conflict with each other in the kitchen when sharing resources. And you have to pay them.
Now does it make sense that multithreading is only one kind of asynchrony? Threading is about workers; asynchrony is about tasks. In multithreaded workflows you assign tasks to workers. In asynchronous single-threaded workflows you have a graph of tasks where some tasks depend on the results of others; as each task completes it invokes the code that schedules the next task that can run, given the results of the just-completed task. But you (hopefully) only need one worker to perform all the tasks, not one worker per task.
It will help to realize that many tasks are not processor-bound. For processor-bound tasks it makes sense to hire as many workers (threads) as there are processors, assign one task to each worker, assign one processor to each worker, and have each processor do the job of nothing else but computing the result as quickly as possible. But for tasks that are not waiting on a processor, you don't need to assign a worker at all. You just wait for the message to arrive that the result is available and do something else while you're waiting. When that message arrives then you can schedule the continuation of the completed task as the next thing on your to-do list to check off.
So let's look at Jon's example in more detail. What happens?
Someone invokes DisplayWebSiteLength. Who? We don't care.
It sets a label, creates a client, and asks the client to fetch something. The client returns an object representing the task of fetching something. That task is in progress.
Is it in progress on another thread? Probably not. Read Stephen's article on why there is no thread.
Now we await the task. What happens? We check to see if the task has completed between the time we created it and we awaited it. If yes, then we fetch the result and keep running. Let's suppose it has not completed. We sign up the remainder of this method as the continuation of that task and return.
Now control has returned to the caller. What does it do? Whatever it wants.
Now suppose the task completes. How did it do that? Maybe it was running on another thread, or maybe the caller that we just returned to allowed it to run to completion on the current thread. Regardless, we now have a completed task.
The completed task asks the correct thread -- again, likely the only thread -- to run the continuation of the task.
Control passes immediately back into the method we just left at the point of the await. Now there is a result available so we can assign text and run the rest of the method.
It's just like in my analogy. Someone asks you for a document. You send away in the mail for the document, and keep on doing other work. When it arrives in the mail you are signalled, and when you feel like it, you do the rest of the workflow -- open the envelope, pay the delivery fees, whatever. You don't need to hire another worker to do all that for you.
In-browser Javascript is a great example of an asynchronous program that has no multithreading.
You don't have to worry about multiple pieces of code touching the same objects at the same time: each function will finish running before any other javascript is allowed to run on the page. (Update: Since this was written, JavaScript has added async functions and generator functions. These functions do not always run to completion before any other javascript is executed: whenever they reach a yield or await keyword, they yield execution to other javascript, and can continue execution later, similar to C#'s async methods.)
However, when doing something like an AJAX request, no code is running at all, so other javascript can respond to things like click events until that request comes back and invokes the callback associated with it. If one of these other event handlers is still running when the AJAX request gets back, its handler won't be called until they're done. There's only one JavaScript "thread" running, even though it's possible for you to effectively pause the thing you were doing until you have the information you need.
In C# applications, the same thing happens any time you're dealing with UI elements--you're only allowed to interact with UI elements when you're on the UI thread. If the user clicked a button, and you wanted to respond by reading a large file from the disk, an inexperienced programmer might make the mistake of reading the file within the click event handler itself, which would cause the application to "freeze" until the file finished loading because it's not allowed to respond to any more clicking, hovering, or any other UI-related events until that thread is freed.
One option programmers might use to avoid this problem is to create a new thread to load the file, and then tell that thread's code that when the file is loaded it needs to run the remaining code on the UI thread again so it can update UI elements based on what it found in the file. Until recently, this approach was very popular because it was what the C# libraries and language made easy, but it's fundamentally more complicated than it has to be.
If you think about what the CPU is doing when it reads a file at the level of the hardware and Operating System, it's basically issuing an instruction to read pieces of data from the disk into memory, and to hit the operating system with an "interrupt" when the read is complete. In other words, reading from disk (or any I/O really) is an inherently asynchronous operation. The concept of a thread waiting for that I/O to complete is an abstraction that the library developers created to make it easier to program against. It's not necessary.
Now, most I/O operations in .NET have a corresponding ...Async() method you can invoke, which returns a Task almost immediately. You can add callbacks to this Task to specify code that you want to have run when the asynchronous operation completes. You can also specify which thread you want that code to run on, and you can provide a token which the asynchronous operation can check from time to time to see if you decided to cancel the asynchronous task, giving it the opportunity to stop its work quickly and gracefully.
Until the async/await keywords were added, C# was much more obvious about how callback code gets invoked, because those callbacks were in the form of delegates that you associated with the task. In order to still give you the benefit of using the ...Async() operation, while avoiding complexity in code, async/await abstracts away the creation of those delegates. But they're still there in the compiled code.
So you can have your UI event handler await an I/O operation, freeing up the UI thread to do other things, and more-or-less automatically returning to the UI thread once you've finished reading the file--without ever having to create a new thread.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I'm struggling to grasp the concept of asynchronousness. Is the following roughly correct about asynchronous operations?
A problem can occur if a piece of code takes a long time to complete. This is because i) it stops code below from running and it might be nice to run this whilst the hard code loads in the background. And ii) Indeed, JS might try to execute the code below before the hard code’s finished. If the code below relies on the hard code, that’s a problem.
A solution is: if an operation takes a long time to complete, you want to process it in a separate thread while the original thread is processed. Just make sure the main thread doesn't reference things that the asynchronous operation returns. JS employs event-ques for this solution. Asynchronous operations are executed in an event-que which executes after the main-thread.
But even the event-que can suffer from the same problem as the main-thread. If fetch1, which is positioned above fetch2, takes a long time to return a promise, and fetch2 doesn’t, JS might start executing fetch2 before executing fetch1. This is where Promise.all is useful because it won't proceed with the next step in the asynchronous operation until both both fetch1 & fetch2’s promises are resolved.
On a separate note, I’ve read when chaining .then, that counts as one asynchronous operation so we can always guarantee that the subsequent .thenwill only execute when the .then before it has executed|resolved its promise.
Almost correct but not quite.
If you are talking about "asynchronousness" the word in the English language then it just means that things can happen out of order. This concept is used in a lot of languages including multithreading in Java and C/C++.
If you are talking about the specific concept of asynchronousness as it relates to node.js or asynchronous I/O in C/C++ then you do have some misunderstandings in how this works at the low level.
A problem can occur if a piece of code takes a long time to complete. This is because i) it stops code below from running and it might be nice to run this whilst the hard code loads in the background. And ii) Indeed, JS might try to execute the code below before the hard code’s finished. If the code below relies on the hard code, that’s a problem.
When talking about javascript or asynchronous I/O in C/C++ (where javascript got its asynchronousness from) this is not true.
What actually happens is that waiting for something to happen may take a long time to complete. Instead of waiting why not tell the OS to execute some code (your callback) once that thing happens.
At the OS level most modern operating systems have API that let you tell it to wake your process up when something happens. That thing may be a keyboard event, a mouse event, an I/O event (from disk or network), a system reconfiguration event (eg. changing monitor resolution) etc.
Most traditional languages implement blocking I/O. What happens is that when you try to read something form disk or network your process goes to sleep immediately and the OS will wake it up again when the data arrives:
Traditional blocking I/O
time
│
├────── your code doing stuff ..
├────── read_data_from_disk() ───────────────────┐
┆ ▼
: OS puts process to sleep
.
. other programs running ..
.
: data arrives ..
┆ OS wakes up your process
├────── read_data_from_disk() ◀──────────────────┘
├────── your program resume doing stuff ..
▼
This means that your program can only wait for one thing at a time. Which means that most of the time your program is not using the CPU. The traditional solution to listen to more events is multithreading. Each thread will seperately block on their events but your program can spawn a new thread for each event it is interested in.
It turns out that naive multithreading where each thread waits for one event is slow. Also it ends up consuming a lot of RAM especially for scripting languages. So this is not what javascript does.
Note: Historically the fact that javascript uses a single thread instead of multithreading is a bit of an accident. It was just the result of decisions made by the team that added progressive JPEG rendering and GIF animations to early browsers. But by happy coincidence this is exactly what makes things like node.js fast.
What javascript does instead is wait for multiple events instead of waiting for a single event. All modern OSes have API that lets you wait for multiple events. They range from queue/kqueue on BSD and Mac OSX to poll/epoll on Linux to overlapped I/O on Windows to the cross-platform POSIX select() system call.
The way javascript handles external events is something like the following:
Non-blocking I/O (also known as asynchronous I/O)
time
│
├────── your code doing stuff ..
├────── read_data_from_disk(read_callback) ───▶ javascript stores
│ your callback and
├────── your code doing other stuff .. remember your request
│
├────── wait_for_mouse_click(click_callback) ─▶ javascript stores
│ your callback and
├────── your code doing other stuff .. remember your request
│
├────── your finish doing stuff.
┆ end of script ─────────────▶ javascript now is free to process
┆ pending requests (this is called
┆ "entering the event loop").
┆ Javascript tells the OS about all the
: events it is interested in and waits..
. │
. └───┐
. ▼
. OS puts process to sleep
.
. other programs running ..
.
. data arrives ..
. OS wakes up your process
. │
. ┌───┘
: ▼
┆ Javascript checks which callback it needs to call
┆ to handle the event. It calls your callback.
├────── read_callback() ◀────────────────────┘
├────── your program resume executing read_callback
▼
The main difference is that synchronous multithreaded code waits for one event per thread. Asynchronous code either single threaded like javascript or multi threaded like Nginx or Apache wait for multiple events per thread.
Note: Node.js handles disk I/O in separate threads but all network I/O are processed in the main thread. This is mainly because asynchronous disk I/O APIs are incompatible across Windows and Linux/Unix. However it is possible to do disk I/O in the main thread. The Tcl language is one example that does asynchronous disk I/O in the main thread.
A solution is: if an operation takes a long time to complete, you want to process it in a separate thread while the original thread is processed.
This is not what happens with asynchronous operations in javascript with the exception of web workers (or worker threads in Node.js). In the case of web workers then yes, you are executing code in a different thread.
But even the event-que can suffer from the same problem as the main-thread. If fetch1, which is positioned above fetch2, takes a long time to return a promise, and fetch2 doesn’t, JS might start executing fetch2 before executing fetch1
This is not what is happening. What you are doing is as follows:
fetch(url_1).then(fetch1); // tell js to call fetch1 when this completes
fetch(url_2).then(fetch2); // tell js to call fetch2 when this completes
It is not that js "might" start executing. What happens with the code above is both fetches are executed synchronously. That is, the first fetch strictly happens before the second fetch.
However, all the above code does is tell javascript to call the functions fetch1 and fetch2 back at some later time. This is an important lesson to remember. The code above does not execute the fetch1 and fetch2 functions (the callbacks). All you are doing is tell javascript to call them when the data arrives.
If you do the following:
fetch(url_1).then(fetch1); // tell js to call fetch1 when this completes
fetch(url_2).then(fetch2); // tell js to call fetch2 when this completes
while (1) {
console.log('wait');
}
Then the fetch1 and fetch2 will never get executed.
I'll pause here to let you ponder on that.
Remember how asynchronous I/O is handled. All I/O (often called asynchronous) function calls don't actually cause the I/O to be accessed immediately. All they do is just remind javascript that you want something (a mouse click, a network request, a timeout etc.) and you want javascript to execute your function later when that thing completes. Asynchronous I/O are only processed at the end of your script when there is no more code to execute.
This does mean that you cannot use an infinite while loop in a javascript program. Not because javascript does not support it but there is a built-in while loop that surrounds your entire program: this big while loop is called the event loop.
On a separate note, I’ve read when chaining .then, that counts as one asynchronous operation.
Yes, this is by design to avoid confusing people on when promises are processed.
If you are interested at how the OS handles all this without further creating threads you may be interested in my answers to these related questions:
Is there any other way to implement a "listening" function without an infinite while loop?
node js - what happens to incoming events during callback excution
TLDR
If nothing else I'd like you to understand two things:
Javascript is a strictly synchronous programming language. Each statement in your code is executed strictly sequentially.
Asynchronous code in all languages (yes, including C/C++ and Java and Python etc.) will call your callback at any later time. Your callback will not be called immediately. Asynchronousness is a function-call level concept.
It's not that javascript is anything special when it comes to asynchronousness*. It's just that most javascript libraries are asynchronous by default (though you can also write asynchronous code in any other language but their libraries are normally synchronous by default).
*Note: of course, things like async/await does make javascript more capable of handling asynchronous code.
Side note: Promises are nothing special. It is just a design pattern. It is not something built-in to javascript syntax. It is just that newer versions of javascript comes with Promises as part of its standard library. You could have always used promises even with very old versions of javascript and in other languages (Java8 and above for example call have promises in their standard library but call them Futures).
This page explains Node.js event loop very well (since it's by Node.js):
https://nodejs.dev/learn/the-nodejs-event-loop
A problem can occur if a piece of code takes a long time to complete.
This is because i) it stops code below from running and it might be
nice to run this whilst the hard code loads in the background. And ii)
Indeed, JS might try to execute the code below before the hard code’s
finished. If the code below relies on the hard code, that’s a problem.
Yes, though to reword: having a user wait for code to resolve is bad user experience rather than a runtime error. Still, a runtime error would indeed occur if a code block was dependent on a variable that returned undefined because it had yet to resolve.
A solution is: if an operation takes a long time to complete, you want
to process it in a separate thread while the original thread is
processed. Just make sure the main thread doesn't reference things
that the asynchronous operation returns. JS employs event-ques for
this solution. Asynchronous operations are executed in an event-que
which executes after the main-thread.
Yes, but it is important to point out these other threads are occurring in the browser or on an api server, not within your JS script. Also, async functions are still called in the main call stack, but their resolve is placed in either the job queue or message queue.
But even the event-que can suffer from the same problem as the
main-thread. If fetch1, which is positioned above fetch2, takes a long
time to return a promise, and fetch2 doesn’t, JS might start executing
fetch2 before executing fetch1. This is where Promise.all is useful
because it won't proceed with the next step in the asynchronous
operation until both both fetch1 & fetch2’s promises are resolved.
Yes, a promise's resolve is executed as soon as the current function in the call stack resolves. If one promise resolves before another, its resolve will executed first event if it was called second. Also note that Promise.all doesn't change the resolve time, but rather returns the resolves together in the order their promise was executed.
On a separate note, I’ve read when chaining .then, that counts as one
asynchronous operation so we can always guarantee that the subsequent
.thenwill only execute when the .then before it has executed|resolved
its promise.
Yes, though the newer and cleaner syntax is async await:
function A () {
return new Promise((resolve, reject)=> setTimeout(()=> resolve("done"),2000))
}
async function B () {
try {
console.log("waiting...");
const result = await A();
console.log(result);
} catch (e) {
console.log(e);
}
}
B();
And below shows the Node.js callstack in action:
function A () {
return new Promise((resolve, reject)=> resolve(console.log("A")))
}
function B () {
console.log("B");
C();
}
function C () {
console.log("C");
}
function D () {
setTimeout(()=> console.log("D"),0);
}
B();
D();
A();
B gets called, C gets called, B resolves, D gets called, setTimeout gets called but its resolve is moved to the message queue, D resolves, A gets called, the promise gets called and immediately resolves, A resolves, the call stack completes, the message queue is accessed
Mainly looking at the FS api, for most functions it seems there are three flavors to choose from:
Synchronous
Asynchronous using callback
Asynchronous using promises
Async is the superior way to use system resources, however, if I'm already inside an async function and am awaiting every call anyway then there shouldn't be any difference between that and just using synchronous calls, right? To me it just seems like a built in await statement.
I don't know how async is implemented in js/node though. Is there any advantage to using async functions if I'm inside an async function to begin with? (excluding scenarios when I'm running async tasks in parallel)
One should decide to use an async function ONLY based on what is going on inside that function, not on who is calling it. The caller does not affect whether a function should be async or not.
Reasons to make a function async:
You have promise-based asynchronous operations inside the function and you wish to use await.
You have promise-based asynchronous operations inside the function and you wish to take advantage of the automatic catching of synchronous exceptions (and conversion to a rejected promise) that might occur before you invoke your asynchronous operations.
And, that's pretty much it for the reasons to use the async keyword in front of a function.
Things that an async function is NOT (or common misconceptions about async functions):
It doesn't magically make blocking code become non-blocking.
It doesn't make the caller run faster.
It doesn't make synchronous code now run in the background asynchronously.
Async is the superior way to use system resources,
Not sure what you mean there. Asynchronous functions allow you to run operations in a non-blocking fashion so that the main thread in Javascript can do other things while the asynchronous operation is running, but that is not something that an async function enables. That's enabled by an asynchronous operation. The two are different.
if I'm already inside an async function and am awaiting every call anyway then there shouldn't be any difference between that and just using synchronous calls, right?
Incorrect. Using await with a function that returns a promise does suspend execution of the current function (returning a promise immediately), but that allows the main Javascript thread to do other things, serve other requests, etc... Using synchronous code would be blocking and would not allow the main thread to do other things, thus ruining the scalability of a server.
To me it just seems like a built in await statement.
Blocking, synchronous code affects everything else that could be running during your operation. It's not the same as using await.
async/await is not equivalent to synchronous execution; it's syntactic sugar to make working with promises easier (indeed, the goal of these keywords is to make promises closer to writing synchronous code from a programming standpoint and therefore more intuitive to use).
async places a task on the event loop which will execute after all synchronous execution pending on the stack finishes. The advantages of this are clear: the process can do work while waiting for resources to be available (opening a file involves a system call, for example, so it makes sense to make this a non-blocking operation).
If you're already inside an asynchronous function, the advantages and drawbacks of asynchronous operations are just the same as they would be anywhere else. In fact, await can only be used in an async function.
Have read tons of articles and docs, however this topic still not clear enough to me. Quote from one answer https://stackoverflow.com/a/46004461/630169:
As long as the code contained inside the async/await is non-blocking
it won't block, for example, db calls, network calls, filesystem calls.
But if the code contained inside async/await is blocking, then it will
block the entire Node.js process, for example, infinite loops, CPU
intensive tasks like image processing, etc.
However, Understanding the node.js event loop says:
Of course, on the backend, there are threads and processes for DB
access and process execution.
In C# it is enough to write function marked with async and call with await so .Net puts it in another thread. However, it confused me things organized differently in Node.js and async/await function still could block the main thread.
So the question is: how to write (organize) arbitrary async/await function in node.js to be sure it will run asynchronously in separate thread or process? Is there good code example? Some npm module? Also good to have it not much trickier than C# variant. Thanks!
Some function example to made it non-blocking, for example, if I want synchronous DB call to make asynchronous (non-blocking):
var Database = require('better-sqlite3');
var db = new Database('./my_db.sqlite');
async function DBRequest() {
var row = db.prepare("SELECT * FROM table");
return row;
};
Note: better-sqlite3 — synchronous module.
Well here's some example code. Decided it was a worthwhile exercise to provide it.
You can write long-running blocking code in such a way that it can yield execution time to other functions
var array = new Array(100);
function processNext(){
if (array.length === 0) return;
var item = array.shift(); // gets first item from array and removes it.
process(item); // 0.5 seconds of blocking time
setTimeout(processNext ,500); // wait 0.5 seconds and then process the next one
// during this waiting time, other code will run on your server.
}
processNext();
Admittedly I'm a novice and this may be a very bad idea for reasons I don't know about.
You're really at the mercy of the library your using here - if the code is synchronous and not I/O bound then there's really not much else you can do within your Node process to make it asynchronous.
Your only real alternative is to move that code into it's own process which consequently makes it I/O bound, that way your app can wait on it and not block it's own thread.
My interest was not for nothing - similar questions people asked before me, as well as on stackoverflow (and here):
But what's with longish, CPU-bound tasks?
How do you avoid blocking the event loop, when the task is at hand is
not I / O bound, and lasts more than a few fractions of a millisecond?
You simply can not, because there's no way ... well, there was not
before threads_a_gogo.
and to solve them they have already created a bunch of modules, and some, such as threads, work both in the browser and in Node.js:
threads
Threads à gogo
nPool
threadpool-js
threadpool
etc.
Good if someone could attach async/await to them or provide good example - that would be nice.
By the way, here's a comrade tests driven on Threads à gogo - results with threads is 40x faster than with Cluster. So single threaded idea of Node.js does not always work well.
I'm currently learning Dart, but this is also applicable to what's going on in the JavaScript world right now, and it seems like C# also uses the same pattern.
In Dart, any function that uses await must itself be labeled asynchronous through async as follows:
import "dart:html";
main() async {
var context = querySelector("canvas").context2D;
var running = true;
while (running) {
var time = await window.animationFrame;
...
}
}
This does not make sense to me. If a function is waiting on an asynchronous function to complete, is it not then considered blocking? Why do JS and Dart require it to be labeled asynchronous? Would it not be the opposite?
To me it would make far more sense if the calling function must use the async keyword if it calls any function that also includes it in its definition. In this pattern, await would be used to convert asynchronous functions to synchronous ones.
This way would also avoid duplicate functions, since right now, libraries seem to always have func() and funcSync() or funcAsync().
The basic semantics of async/await are the same across F#, VB, C#, Python, Dart, Hack, and JavaScript. So I think this question has sufficient answers from other languages. But since it has been reopened...
If a function is waiting on an asynchronous function to complete, is it not then considered blocking?
No. Think about it this way:
"asynchronous" means "does not block the calling thread".
"synchronous" means "blocks the calling thread".
In an asynchronous method/function, the method/function can be paused at the await points, but it does not block the calling thread while it is paused. The function runs serially (one statement at a time), but asynchronously (without blocking the calling thread).
To me it would make far more sense if the calling function must use the async keyword if it calls any function that also includes it in its definition.
That's how it already works... await consumes promise/future/task-returning methods/functions, and async marks a method/function as capable of using await.
This way would also avoid duplicate functions
This is not possible with historically-blocking imperative languages. A method/function either blocks the calling thread until it is complete, or it does not. It is either synchronous or asynchronous.
There are some interesting alternative approaches to async methods/functions, though:
Go is not historically blocking; you can think of it as a language where every method/function is potentially asynchronous; doing this in any other runtime would be disastrous, but Go avoids those problems by implementing a strict goroutine system with message passing - no shared memory or threads allowed.
Another example are pure functional languages, where Future is just another monad and requires no special compiler support for async/await keywords.
In Dart async indicates that the code containing await needs to be rewritten.
async/await is just syntactic sugar for the Future.then() base API, and the code is rewritten to this canonical Future based form, before it is compiled and executed.
Therefore await doesn't make code blocking.
There are also other supported markers like *sync and *async for generators.
See also
- Dart async/await internals
- https://www.dartlang.org/articles/language/await-async
I'm not sure what your question has to do with C# but await is a most unfortunate keyword choice in C#. await is more understandable if you read it as resume after or even yield then resume after. When execution encounters await, it suspends the current function, returning to its caller. Once the Task being waited on is done, execution resumes after the await when the caller needs the result (from an await expression of its own).
This is a fundamental misunderstanding of what's going on "under-the-hood", I'm assuming the javascript async/await implementation mirrors (at least conceptually) that of the .NET world (which originated in F#).
Essentially:
A "unit of work" "token" of sorts (in C# a Task in JS a Promise) represents a completion of a task with an option of returning a value.
An "asynchronous" method is marked with async, to indicate to the compiler/interpreter/runtime whatever, that this method will return said token, and will likely consume some as well.
The thingamajig running it all, will (in C#'s case), rewrite the code on the sly to essentially do the following:
Start async method
Do standard normal code
Encounter "token" providing method
Call it, grab token
Setup a place the code can jump back to later
Is the token complete? If so, carry on, If not, set a callback to have the runtime come back to this place when it does
In this expanded context, the keywords make sense:
async(hronous) - A method that does some task that can take an indeterminate amount of time, that can be waited upon.
await - Indicates that instead of just grabbing the token from the async method and doing nothing with it, that you actually want to set up all this ceremony around listening out for when the work is done, and carrying on afterwards.
tl;dr
Just think of async and await as invisible callbacks, async indicates when something can be listened out for, and await is what actually does the listening.