2012-04-16 159 views
12

我们正面临将基于自定义代码的REST服务转换为Web API的任务。该服务具有大量的请求,并对可能需要一些时间加载的数据进行操作,但是一旦加载,它可以被缓存并用于服务所有传入的请求。以前版本的服务将有一个线程负责加载数据并将其存入缓存。为防止IIS耗尽工作线程,客户端会在缓存准备就绪之前收到“稍后回来”响应。Web API并发性和可伸缩性

我对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容器中注册并注入到控制器中。带有LazyThreadSafetyMode.ExecutionAndPublication的Lazy确保只有第一个线程/请求正在运行初始化代码,下列请求将被阻塞,直到初始化完成。

将网页API能够处理1000个请求在等待,而其他请求不打懒这个正在服务和没有IIS耗尽工作线程的初始化完成?

回答

10

从动作返回Task<T>将允许代码在后台线程(线程池)上运行并释放IIS线程。因此,在这种情况下,我会改变

public IEnumerable<Contact> Get() 

public Task<IEnumerable<Contact>> Get() 

记得返回开始任务,否则线程将只坐,什么也不做。

懒惰的实现虽然很有用,但与Web API的行为没有多大关系。所以我不会对此发表评论。无论是否使用懒惰,基于任务的返回类型都是进行长时间运行操作的方式。

我有两篇博文可能对您有用:herehere