单核心机器上的Web API和Async/Await优势

Mic*_*ael 2 c# azure task-parallel-library asp.net-web-api

我曾在一个不同的主题中询问过一个关于GPL +在TPL(异步/等待)中的问题的问题,讨论转向了这样一个问题:使用TPL是否有任何好处.

所以我试图在这里理解答案.

情景大致是这样的:

  • Web API控制器/方法接收图像上载
  • 调整图像大小并将其上传到azure的方法被调用多次,用于各种大小(<10)
  • 该方法为每个已调整大小和上载的图像返回一个Uri
  • 响应将返回给Web API客户端

请注意,这可能会在单个核心计算机上运行,​​因此并行运行所有调整大小(例如,缩短请求的总长度)不会带来任何好处.

但我的印象是将所有各种调整大小包装到一个方法中并且异步运行至少将Web API线程暂时返回到池,以处理另一个请求(当常规线程运行调整大小任务时),以及那是件好事.代码如下所示:

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;
}
Run Code Online (Sandbox Code Playgroud)

和...

var photoUris = await Task.Run(() => _photoService.ProcessImages(photoStream);
Run Code Online (Sandbox Code Playgroud)

所以问题是 - 我是不是基地?也许理论是合理的,但它没有得到很好的实现(也许我需要使用ConfigureAwait)?

这里的现实是什么?

Ste*_*ary 5

但我的印象是将所有各种调整大小包装到一个方法中并且异步运行将至少将Web API线程暂时返回到池,以处理另一个请求(当常规线程运行调整大小任务时),以及那是件好事.

不,不是真的.如果你有真正的异步工作要做,那么是的,你可以从使用async和获得可扩展性的好处await.但是,您的工作受CPU限制,因此代码如下:

var photoUris = await Task.Run(() => _photoService.ProcessImages(photoStream);
Run Code Online (Sandbox Code Playgroud)

最后使用另一个线程池thread(Task.Run),允许请求线程返回到线程池.所以它实际上增加了开销,并没有给你任何可扩展性的好处.

在ASP.NET上,如果要进行CPU绑定工作,只需直接调用该方法即可.不要把它包起来Task.Run.

  • 关于他们的唯一"特殊"是他们有一个请求上下文.它们仍然是线程池线程,来自`Task.Run`使用的相同线程池,并且通过"窃取"这些线程并稍后"注入"它们,您可以抛弃线程池的启发式.因此,ASP.NET上的"Task.Run"几乎没有任何用例.Azure上传将受I/O限制,因此非常适合"async".由于您有混合工作(CPU绑定,然后是I/O绑定),请同步执行CPU绑定工作,然后异步执行I/O绑定工作.不要使用`Task.Run`. (2认同)