When working with asynchronous web services, what should and shouldn't wait?

I am developing an MVC web application that allows me to manage my data asynchronously through a web service.

Understandably, this allows CPU threads to access the application pool for the server that this website is running on to return to the application pool after a request, so that they can be used to serve other requests without stopping the entire thread.

Assuming my understanding is correct (although it might be poorly formulated), I have to think about when I owe await

things. Consider the following function:

public async Task<ActionResult> Index()
{
    List<User> users = new List<User>();
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://localhost:41979");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(
                       new MediaTypeWithQualityHeaderValue("application/json"));

        HttpResponseMessage response = await client.GetAsync("api/user/");

        if (response.IsSuccessStatusCode)
        {
            users = await response.Content.ReadAsAsync<List<User>>();
        }
    }

    return View(users);
}

      

All my functions look the same except they do different things with the data returned by the web service, and I wondered if I shouldn't wait for the return?

Something like:

return await View(users);

      

or

await return View(users);

      

I mean the website has been working very well so far, except that I had some confusion as to what exactly the web service should send to the client's website, but since I am new to development involving web service.I'm still wondering if I'm doing something right, and I've had it for a while now.

+3


source to share


4 answers


You can only wait for named or anonymous methods and lambda expressions that expose an asynchronous operation via Task

, Task<T>

or a custom awaiter. Since View

it doesn't make anything asynchronous by itself, you can't wait for it.

What's the point of using it await

? Usually you have some IO bindings that are asynchronous in nature. By using the async API, you allow a thread to be non-blocking by returning to the thread pool, using it to serve different requests. async

does not change the nature of HTTP. It's still a request-response. When a method async

gives control, it does not return a response to the client . It will only return after completing the action.



View(object obj)

returns a ViewResult

, which in turn converts your object to the desired result. ViewResult

is not expected because it does not reveal any "promises" through the expected object. So you cannot wait on it asynchronously.

+4


source


I need to think about when should I wait for things

It's better to always wait for the result from asynchronous calls.



If you do not expect this, you shoot and forget , you will not receive an answer to your account, both in case of success and in case of errors.

+1


source


"Waiting" when you need to deploy the async task as value. Otherwise, you can check in the task and run it later if needed. Also note that .Wait () is not the same as waiting. Wait () will block until the task completes (note that I know). Also check your code, you have a syntax error in your method signature:

public async <Task>ActionResult> Index()

      

Should be

public async Task<ActionResult> Index()

      

0


source


I think this is a very good question and also very difficult to answer, especially in the case of a website.

I had some confusion as to what the web service should send back to the client site

The most important thing to understand is if you are using async / await then the action method code is still serialized, I mean the next line will only be executed after the async operation completes. However, there will be (at least) three streams:

  • The original worker thread of the web server in which the action method operates is called. Initially, the MVC framework received this thread from the pool and allocated this thread to serve the current request.
  • Optional thread (s) to run on async operation that can be called awaiting.
  • A continuation thread (also a pooled worker) in which your action method continues after waiting. Note this thread will have the same context (HttpContext, custom culture, etc.) as the original worker so that it is transparent to you, but it will be a different thread recently pooled.

At first glance, this doesn't make sense: why are all these focus-focus threads in case the operations in the action method are still serialized? I am taking the same time ... To understand this, we have to look at a desktop application such as a WPF application.

In short: there is a message loop and a dedicated thread that reads the UI (and other virtual) events from the queue and executes event handlers in the context of that thread, like a button click event. If you block this thread for 2 seconds, the UI will become unresponsive for that time. Therefore, we would like to do a lot asynchronously on another thread and allow the dedicated (UI) thread to quickly return and process other messages from the queue. However, this can be very inconvenient because we once wanted to continue something after the asynchronous operation completed and we had a result. The C # async / await feature made this very handy. In this case, the continuation thread is always the dedicated UI thread, but in its (very) later round in an infinite loop. To complete it:

In the event handler, you can use async / await to perform your operations in a serialized way, the continuation will always execute on the original dedicated UI thread, but while this thread is awaiting, it can loop and process other messages.

Now back to the MVC action method: In this case, your action method is analogous to an event handler. Although it is still difficult to understand the use of thread complications: this action method blocking case will not block anything (since it blocked the dedicated UI thread in WPF). Here are the facts:

  • Other client (browser) requests will be served by other threads. (therefore we are not blocking anything by blocking this thread (*) to continue reading
  • This request will not be served faster even if we use async / await, because the operations are serialized and we have to wait (wait) for the result of the async operation. (Don't confuse async / await with parallel processing)

Thus, the use of async / await and transparent threading tricks is not as obvious as in the case of a desktop application.

However: The pool is not an endless resource. By dropping ASAP back into the pool (waiting) of a worker thread originally intended to serve the request, and continuing on a different thread after completion, the async operation can lead to better use of the thread pool and can lead to better server network performance under extreme loads.

0


source







All Articles