Web API and Async/Await Benefits on a Single Core

2019-07-22 03:40发布

I had asked a question in a different thread about issues with GDI+ in TPL (async/await) and the discussion turned to the question of whether or not there even were any benefits to using TPL for this.

So I'm trying to understand the answer to that here.

The scenario is roughly this:

  • A Web API controller/method receives an image upload
  • A method which resizes the image and uploads it to azure is called multiple times for various sizes (<10)
  • The method returns a Uri for each resized-and-uploaded image
  • A response is returned to the Web API client

Note that this will likely run on a single core machine so there is no benefit to be gained by running all the resizes in parallel (to, say, shorten the overall length of the request).

But I'm under the impression that wrapping all the various resizes into a method and running that asynchronously will at least return the Web API thread to the pool, temporarily, to process another request (while a regular thread runs the resizing tasks), and that that is a good thing. The code would look like this:

public Dictionary<ProfilePhotoSize, Uri> ProcessImages(Stream photoStream)
{
    var imgUris = new Dictionary<ProfilePhotoSize, Uri>()
    {
        ProfilePhotoSize.FiveHundredFixedWidth, ResizeAndUpload(ProfilePhotoSize.FiveHundredFixedWidth, photoStream)},
        ProfilePhotoSize.Square220, ResizeAndUpload(ProfilePhotoSize.Square220, photoStream)},
        ProfilePhotoSize.Square140, ResizeAndUpload(ProfilePhotoSize.Square140, photoStream)},
        ProfilePhotoSize.Square80, ResizeAndUpload(ProfilePhotoSize.Square80, photoStream)},
        ProfilePhotoSize.Square50, ResizeAndUpload(ProfilePhotoSize.Square50, photoStream)}
    };

    return imgUris;
}

and...

var photoUris = await Task.Run(() => _photoService.ProcessImages(photoStream);

So the question is - am I off base? Maybe the theory is sound, but it's not implemented quite right (perhaps I need to use ConfigureAwait)?

What's the reality here?

2条回答
成全新的幸福
2楼-- · 2019-07-22 04:17

But I'm under the impression that wrapping all the various resizes into a method and running that asynchronously will at least return the Web API thread to the pool, temporarily, to process another request (while a regular thread runs the resizing tasks), and that that is a good thing.

No, not really. If you had true asynchronous work to do, then yes, you'd get a scalability benefit from using async and await. However, your work is CPU-bound, so code like this:

var photoUris = await Task.Run(() => _photoService.ProcessImages(photoStream);

just ends up using another thread pool thread (Task.Run), allowing the request thread to return to the thread pool. So it's actually adding overhead and doesn't give you any scalability benefit.

On ASP.NET, if you have CPU-bound work to do, just call that method directly. Don't wrap it in Task.Run.

查看更多
We Are One
3楼-- · 2019-07-22 04:20

You could see performance and responsiveness improvements for your asp.net application if it is using too many threads from the thread pool, which can happen if you have a lot of long running requests. If the request queue becomes full, the web server rejects requests with an HTTP 503 status (Server Too Busy). According to Microsoft, there are cases where the performance benefit of async code can be significant:

A web application using synchronous methods to service high latency calls where the thread pool grows to the .NET 4.5 default maximum of 5, 000 threads would consume approximately 5 GB more memory than an application able the service the same requests using asynchronous methods and only 50 threads. When you’re doing asynchronous work, you’re not always using a thread. For example, when you make an asynchronous web service request, ASP.NET will not be using any threads between the async method call and the await. Using the thread pool to service requests with high latency can lead to a large memory footprint and poor utilization of the server hardware

This however, is not the case for CPU-bound operations, only network-bound or I/O-bound.

For more information, have a look at Using Asynchronous Methods in ASP.NET MVC 4, which applies to web hosted Web API applications as well.

查看更多
登录 后发表回答