Asp.net-Web-Api

Web API 並發性和可擴展性

  • April 16, 2012

我們面臨著將基於自定義程式碼的 REST 服務轉換為 Web API 的任務。該服務有大量請求並對可能需要一些時間才能載入的數據進行操作,但一旦載入,它就可以被記憶體並用於為所有傳入請求提供服務。該服務的先前版本將有一個執行緒負責載入數據並將其放入記憶體中。為了防止 IIS 用盡工作執行緒,客戶端將獲得“稍後再回來”響應,直到記憶體準備好。

我對 Web API 的理解是,它通過對任務進行操作來內置非同步行為,因此請求的數量與所持有的物理執行緒的數量沒有直接關係。

在服務的新實現中,我計劃讓請求等到記憶體準備好,然後做出有效回复。我做了一個非常粗略的程式碼草圖來說明:

public class ContactsController : ApiController
{
   private readonly IContactRepository _contactRepository;

   public ContactsController(IContactRepository contactRepository)
   {
       if (contactRepository == null) 
           throw new ArgumentNullException("contactRepository");
       _contactRepository = contactRepository;
   }

   public IEnumerable<Contact> Get()
   {
       return _contactRepository.Get();
   }
}

public class ContactRepository : IContactRepository
{
   private readonly Lazy<IEnumerable<Contact>> _contactsLazy;

   public ContactRepository()
   {
       _contactsLazy = new Lazy<IEnumerable<Contact>>(LoadFromDatabase, 
           LazyThreadSafetyMode.ExecutionAndPublication);
   }

   public IEnumerable<Contact> Get()
   {
       return _contactsLazy.Value;
   }

   private IEnumerable<Contact> LoadFromDatabase()
   {
       // This method could be take a long time to execute.
       throw new NotImplementedException();
   }
}

請不要在程式碼設計中投入太多價值——它只是為了說明問題而建構的,並不是我們在實際解決方案中是如何做到的。IContactRepository 在 IoC 容器中註冊為單例,並註入到控制器中。Lazy 與 LazyThreadSafetyMode.ExecutionAndPublication 確保只有第一個執行緒/請求正在執行初始化程式碼,隨後的 rquest 被阻塞,直到初始化完成。

Web API 是否能夠處理等待初始化完成的 1000 個請求,而其他未命中此 Lazy 的請求正在被服務並且 IIS 不會耗盡工作執行緒?

從操作返回Task<T>將允許程式碼在後台執行緒 (ThreadPool) 上執行並釋放 IIS 執行緒。所以在這種情況下,我會改變

public IEnumerable<Contact> Get()

public Task<IEnumerable<Contact>> Get()

記住要返回一個已啟動的任務,否則執行緒只會坐在那裡什麼都不做。

延遲實現雖然很有用,但與 Web API 的行為幾乎沒有關係。所以我不會對此發表評論。無論有沒有惰性,基於任務的返回類型都是長時間執行的操作的方式。

我有兩篇關於這方面的博文,可能對你有用:這里這裡

引用自:https://stackoverflow.com/questions/10173933