C# 多个呼叫者等待长时间运行的GET,有没有办法让他们都等待相同的返回?
我正在运行WCF REST服务,发现了一点瓶颈。基本上,当前代码可归结为以下内容:C# 多个呼叫者等待长时间运行的GET,有没有办法让他们都等待相同的返回?,c#,wcf,rest,C#,Wcf,Rest,我正在运行WCF REST服务,发现了一点瓶颈。基本上,当前代码可归结为以下内容: private static List<Widget> widgets; public async Task<List<SearchResult>> Search(string term) { if(widgets == null) { // This call takes up to 60 seconds widgets = aw
private static List<Widget> widgets;
public async Task<List<SearchResult>> Search(string term)
{
if(widgets == null) {
// This call takes up to 60 seconds
widgets = await GetWidgets();
}
return SearchUtil.Search(term, widgets);
}
私有静态列表小部件;
公共异步任务搜索(字符串术语)
{
if(widgets==null){
//此呼叫最长需要60秒
widgets=等待GetWidgets();
}
返回SearchUtil.Search(术语、小部件);
}
问题是许多请求可以进入if检查并调用这个长时间运行的操作。相反,我希望任何额外的传入请求基本上等待原始调用完成,并且只对GetWidgets()进行一次调用。我如何才能做到这一点,这样当字典是空的时,我就不再发出许多请求了
作为一个小插曲,是否可以安全地假设此列表/字典将在服务活动的整个时间内保持填充状态?或者它会因为某种原因而变空吗?处理这种情况的最佳方法是什么(我猜是其他缓存机制)
谢谢 如果不提供线程安全的机制来锁定widgets对象,直到第一个请求完成,这是不完全可能的。由于WCF服务是异步的,许多请求可以开始调用
widgets=await GetWidgets()立即编码>方法
我建议使用简单的锁,例如:
private static List<Widget> widgets;
static readonly object _widgetsLock = new object();
public async Task<List<SearchResult>> Search(string term)
{
if(widgets == null) {
// This call takes up to 60 seconds
lock(_widgetsLock)
if(widgets == null)
widgets = await GetWidgets();
}
return SearchUtil.Search(term, widgets);
}
私有静态列表小部件;
静态只读对象_widgetsLock=new object();
公共异步任务搜索(字符串术语)
{
if(widgets==null){
//此呼叫最长需要60秒
锁(_widgetsLock)
if(widgets==null)
widgets=等待GetWidgets();
}
返回SearchUtil.Search(术语、小部件);
}
只需锁定\u widgetsLock
对象,该对象将通过lock方法停止所有其他执行,直到释放锁。现在,一旦锁被释放,如果有一个等待的线程访问该代码,它就会仔细检查小部件
实际上是否仍然为空(以前的尝试可能已经加载了它)
在应用程序开始处理请求之前,您还可以在应用程序启动时加载小部件。如果我理解正确,您需要一个永远不会过期的缓存,并在第一次有人请求值时填充它。以一种通用的方式进行构建应该非常简单:
class NonExpiringLazyLoadingCache<T>
{
private readonly Func<Task<T>> _factory;
private Task<T> _retrievalTask;
private readonly object _lockObject = new object();
public NonExpiringLazyLoadingCache(Func<Task<T>> factory)
{
this._factory = factory;
}
public async Task<T> GetValue()
{
lock (this._lockObject)
if (this._retrievalTask == null)
this._retrievalTask = this._factory();
await this._retrievalTask;
return this._retrievalTask.Result;
}
}
至于对象的生存期,则取决于WCF服务的托管位置。只要进程保持活动状态,该值通常会保持不变。对于IIS托管的服务,当应用程序池被回收时,该值将被清除。不幸的是,锁体中不能有“wait”。我已经找到了一些方法来完成类似的事情。
private static NonExpiringLazyLoadingCache<List<Widget>> cache = new NonExpiringLazyLoadingCache<List<Widget>>(GetWidgets);
...
var widgets = await cache.GetValue();