问题
In Javascript I am used to making API calls, using whatever library, using the await
keyword. This effectively implements a promise and prevents the next line of code from executing until that line of code has completed.
const response = await fetch("http://some-url.com/endpoint", { /* options */ });
const result = response.json();
This does not seem to be necessary in C#. I can make a thread-blocking call and it won't proceed to the next line without using await
at all.
var response = someApi.get("http://some-url.com/endpoint");
var str = "This line will wait for get() to complete";
Further complicating things, I see many C# libraries have two methods for making an API call - get() and getAsync().
Does C# implement the functionality that the await
keyword in JS gives us natively? What then is the point of these async
methods in C#? I understand JS is single thread, but isn't every C# console app also single threaded until you start making your own threads within it?
回答1:
First of all its not entirely fair to compare C# to JavaScript - they are different languages with different runtimes and different asynchronous mechanisms.
JavaScript is not multi-threaded - it runs on one thread; hence cant actually do anything asynchronously. To over overcome this the JS runtime makes use of the event loop which lets you differentiate between code that needs to block the main thread and code that that shouldnt block (like and AJAX call - once an http request is sent there is nothing JS can do but wait, so instead it gets thrown on the event loop until the the http response is returned, then it will get pulled off the event loop and start executing and code that depends on the response). The 'async' and 'await' keywords are effectively syntactic sugar to wrap the functionality of a Promise: the following code -
function async makeCall()
{
const response = await makeHttpCall(httpRequest);
console.log(response);
}
is similar to (but not exactly the same as) -
function makeCall()
{
makeHttpCall(httpRequest)
.then(response => console.log(response));
}
A Promise it an example of some code that will be placed on the event loop - JavaScript will schedule the execution of this code so it can run seemingly asynchronously on a single thread.
In C# we actually have many threads to work with so we can perform async operation at the same time. To make this easier C# gives us the Task Parallel Library (TPL) which will provide a series of APIs to make working with multi-threaded and scheduled code execution a lot simpler.
https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-parallel-library-tpl
In the same way as JavaScript - the TPL and C# gives us the same syntactic sugar for the use of the 'async' and 'await' keywords and because C# is a lower level language, more libraries provide two implementations for a developer to use for code that doesn't need to block the current or calling thread.
this will block all execution until the operation is complete (current and calling thread)
HttpResponse response = MakeHttpCall();
this will block the current thread of execution but return execution to the calling thread
HttpResponse response = await MakeHttpCallAsync();
this will start the async operation but will return a Task to track the execution
Task responseTask = MakeHttpCallAsync();
// execute code here while we wait for the http response
HttpResponse response = await responseTask; // or responseTask.Result but not ideal
The TPL (any C# code using the type of Task) will decide if a new thread should be created or if the code should be scheduled on the current thread using the synchronisation context.
It also might be useful to think of the type Task in C# in a similar to the type Promise in JS (obviously not the same but there are similarities)
来源:https://stackoverflow.com/questions/63206606/why-do-you-need-to-await-ajax-calls-in-js-but-not-in-c