2014-03-04 69 views
2

我曾在另一個不同的thread中提出了一個關於TPL中的GDI +問題的問題(async/await),討論轉向了是否存在任何問題爲此使用TPL的好處。單核心機器上的Web API和異步/等待優勢

所以我試圖理解這裏的答案。

場景大致是這樣的:

  • 一個Web API控制器/方法接收一個圖像上載
  • 其調整大小的圖像,並將其上傳至天青被多次調用用於各種尺寸的方法(< 10 )
  • 該方法返回一個開放的每個調整大小和上傳的圖像
  • 響應被返回給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; 
} 

和...

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

所以,問題是 - 我是大錯特錯?也許這個理論是正確的,但是它沒有被正確實施(可能我需要使用ConfigureAwait)?

這裏的現實是什麼?

+2

看看這裏http://www.tugberkugurlu.com/archive/how-and-where-concurrent-asynchronous-io-with-asp-net-web-api另外,爲什麼不使用Azure WebJobs來調整圖像大小和上傳到Azure存儲? –

+0

@MatijaGrcic閱讀你的鏈接,它似乎支持我的理解 - 是的?至於Azure WebJobs,我們可能會離開Azure,但如果我們不這樣做,我會着眼於它...... – Michael

回答

2

你可以看到性能和響應速度的改善你的asp.net應用程序如果使用過多的線程的線程池,如果你有很多長時間運行的請求,它可以發生。如果請求隊列已滿,則Web服務器將拒絕HTTP 503狀態(服務器太忙)的請求。據微軟稱,存在這種情況的異步代碼的性能優勢可以顯著:

使用同步方法,其中線程池增長到.NET 4.5默認最大的5到服務的高延遲調用Web應用程序, 000線程會比使用異步方法和只有50個線程的應用程序能夠使用相同的請求消耗大約5 GB的內存。當你在做異步工作時,你並不總是使用一個線程。例如,當您發出異步Web服務請求時,ASP.NET將不會在async方法調用和await之間使用任何線程。使用線程池以高延時服務請求可能導致服務器硬件

的大容量內存和利用率低下然而,這並不是CPU綁定操作的情況下,只有網絡綁定或我/ O結合

欲瞭解更多信息,看看Using Asynchronous Methods in ASP.NET MVC 4,它適用於網絡託管的Web API應用程序。

+0

事情是,他並沒有減少運行線程的數量。 – usr

+0

你能更具體嗎?您嘗試了多少個併發請求,線程池的大小是多少? – elolos

5

但我的印象是,將所有各種大小調整到一個方法並異步運行將至少將Web API線程暫時返回到池,以處理另一個請求(而普通線程運行調整任務),這是一件好事。

不,不是真的。如果你有真正的異步工作要做,那麼是的,你會從使用asyncawait獲得可伸縮性優勢。然而,你的工作是CPU密集型的,所以這樣的代碼:

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

剛剛結束了使用另一個線程池中的線程(Task.Run),允許請求線程返回線程池。所以它實際上是加上開銷,並沒有給你任何可擴展性的好處。

在ASP.NET上,如果你有CPU綁定的工作要做,就直接調用該方法。請勿將其包裝在Task.Run中。

+0

暫時擱置額外的Azure上傳文件(不受CPU綁定) - 我瞭解處理web api請求的線程是「特殊」的,我們可以在長時間運行的任務中使用上述代碼釋放它們(因爲它在非「特殊」線程上執行),並且這很好。我猜測我所瞭解的某些部分是不正確的,但我不清楚哪一部分。然後,如果我們重新介紹Azure上傳文件? – Michael

+2

關於他們唯一「特殊」的是他們有一個請求上下文。它們仍然是線程池線程,來自Task.Run使用的線程池,並且通過「竊取」這些線程並在稍後「注入」它們,您可以拋開線程池的啓發式。所以在ASP.NET上幾乎沒有用於Task.Run的用例。 Azure上傳將被I/O限制,因此非常適合'async'。由於混合工作(CPU綁定,然後I/O綁定),同步執行CPU綁定工作,然後I/O綁定異步工作。不要使用'Task.Run'。 –

+0

太棒了!我們正在誤解我的根源!我們不能在非ThreadPool線程上運行這個CPU綁定的代碼,並且沒有簡單的方法來改變這種行爲(例如,我不想卸載到服務)? – Michael