我们面临着将基于自定义代码的 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 不会耗尽工作线程?