4

在書臨ASP.NET MVC 4有一個異步操作的例子:ASP.NET MVC什麼線程池用於自定義任務?

public class RemoteDataController : AsyncController 
{ 
public async Task<ActionResult> ConsumeAsyncMethod() { 
    string data = await new RemoteService().GetRemoteDataAsync(); 
    return View("Data", (object)data); 
} 
} 


public class RemoteService 
{ 
    public async Task<string> GetRemoteDataAsync() { 
    return await Task<string>.Factory.StartNew(() => { 
      Thread.Sleep(2000); 
      return "Hello from the other side of the world"; 
     }); 
    } 
} 

我的問題是:會的任務不只是使用一個線程從也用於服務請求的線程池?

假設我有一個同步I/O綁定方法。我認爲使用Task.Run調用此方法並在我的操作中等待不會導致可以同時處理更多的請求,因爲I/O綁定方法的任務不再可用於請求處理。還是有一個單獨的線程池只爲請求和使用Task.Run中的動作自動使用不同的?我想到的是這個問題:Using ThreadPool.QueueUserWorkItem in ASP.NET in a high traffic scenario答案或多或少只有來自庫的異步方法應該被使用,這些庫使用自己的線程池。

是否可以配置行爲?它是否以與ASP.NET WebForms相同的方式工作?

回答

4

例如

這是一個非常窮的例子。有三件事,我立即看到它錯了,但主要是你指出:

該任務不只是使用線程池也用於服務請求的線程?

是的,這個例子會。

請改爲考慮這個例子:

public class RemoteDataController : Controller 
{ 
    public async Task<ActionResult> ConsumeAsyncMethod() { 
    string data = await new RemoteService().GetRemoteDataAsync(); 
    return View("Data", data); 
    } 
} 

public class RemoteService 
{ 
    public async Task<string> GetRemoteDataAsync() { 
    await Task.Delay(2000); 
    return "Hello from the other side of the world"; 
    } 
} 

原例如使用Thread.Sleep阻塞線程池線程。這在ASP.NET中完全適得其反。一般來說,不要在ASP.NET上使用Task.Factory.StartNewTask.Run

相反,Task.Delay是自然異步操作。對於「自然異步」,我的意思是異步,就像I/O操作是異步的(例如,用於Web調用的HttpClient)一樣。自然異步操作不使用線程,因此它們對ASP.NET服務器的吸引力(降低線程池的壓力,使您可以擴展更多)。

想一想這是如何工作的:有趣的是當你使用自然異步方法時,一個線程啓動請求直到它到達await;此時請求線程返回到線程池(!),並在接下來的兩秒鐘內有號線程處理該請求(但請求尚未完成)。我喜歡稱這種現象爲「零線程併發」。當Delay完成時,線程恢復處理請求並完成它。

在旁註中,AsyncController是來自MVC3的剩餘物。它不需要async/await

+0

我相信你在這裏是故意的簡單化,但我認爲這意味着沒有線程被使用是有點危險的。沒有*線程池線程正在被使用,但取決於正在完成的工作,系統上可能還有其他線程正在使用。 'Task.Delay',具體來說不會需要一個線程,但還有其他的東西可能。然而,從網絡應用的角度來看,是的,這將是「無線」的工作,所以沒有錯,只是不完全準確。 –

+0

@ChrisPratt:我的意思是沒有線程正在使用該請求。在系統(和應用程序)的其他地方有各種線程在做事情,如果你阻塞了請求線程,那些相同的線程仍然會在那裏做同樣的事情。 即使'Task.Delay':BCL實際上有一個負責所有管理定時器的「定時器線程」,所以有一個用於定時器的BCL線程。但它是整個AppDomain中的一個線程,而不是每個定時器。同樣的原則在這裏:我們正在避免每個請求都需要額外線程的情況。 –