C# 在后台运行查询会增加CPU使用率

C# 在后台运行查询会增加CPU使用率,c#,linq,cpu-usage,C#,Linq,Cpu Usage,我有一个每隔几秒钟运行一次的函数 private void MyTimer_Tick(object sender, EventArgs e) { Task.Run(() => UpdateData()); } private void UpdateData() { //i have some other functions here updateCache(list1, cachelist); } private void updateCache(List<T&

我有一个每隔几秒钟运行一次的函数

private void MyTimer_Tick(object sender, EventArgs e)
{
  Task.Run(() => UpdateData());
}

private void UpdateData()
{ 
  //i have some other functions here 
  updateCache(list1, cachelist);
}


private void updateCache(List<T> searchResults, List<T> cacheList)
{
   var result = searchResults.Where(x => !cacheList.Any(y => x.Number == y.Number && x.FileName == y.FileName));
   cacheList.AddRange(result);
}
private void MyTimer\u勾选(对象发送方,事件参数e)
{
运行(()=>UpdateData());
}
私有void UpdateData()
{ 
//我这里还有一些其他的功能
updateCache(列表1,缓存列表);
}
私有void updateCache(列表搜索结果、列表缓存列表)
{
var result=searchResults.Where(x=>!cacheList.Any(y=>x.Number==y.Number&&x.FileName==y.FileName));
cacheList.AddRange(结果);
}

updateCache()函数中的linq查询正在尝试比较两个列表,如果在cachelist中找到新值,则更新list1。这个linq查询增加了非常高的CPU使用率,由于这个函数每隔几秒钟运行一次,只要窗口打开,CPU使用率就会非常高。如何改进此功能?

缓存列表
设置为
哈希集
字典
,这样您就不必再对其进行循环


另一个选项是将searchResults设置为不同的类型,并在添加项时为其提供一个事件,然后订阅该事件以将该项添加到cacheList中。但这实际上取决于您的体系结构是否允许它。

您可以像下面提供的解决方案那样做。性能问题的一部分可能是无意/不受控制的并发。如果希望updateCache同时运行多次,那么应该引入一些代码来控制它(调节线程数等)。但你可能不想要也不需要。更好的解决方案可能是防止重新进入updateCache

    object _updateLock = new object();
    bool _isUpdating = false;
    bool IsUpdating
    {
        get { return _isUpdating; }
        set
        {
            lock (_updateLock)
            {
                _isUpdating = value;
            }
        }
    }

    private void UpdateData()
    {
        if (!IsUpdating)
        {
            IsUpdating = true;
            updateCache(list1, cachelist);
            IsUpdating = false;
        }          
    }


    ConcurrentDictionary<Tuple<int, string>, T> cache = new
          ConcurrentDictionary<Tuple<int, string>, T>();

    public void updateCache()
    {

        foreach (var sr in searchResults)
        {
            var key = new Tuple<int, string>(sr.Number, sr.FileName);
            cache[key] = sr;
        }
    }
object\u updateLock=new object();
bool\u isupdateing=false;
布尔正在更新
{
获取{return}
设置
{
锁定(_updateLock)
{
_isUpdating=值;
}
}
}
私有void UpdateData()
{
如果(!正在更新)
{
IsUpdating=true;
updateCache(列表1,缓存列表);
IsUpdating=false;
}          
}
ConcurrentDictionary缓存=新建
ConcurrentDictionary();
公共void updateCache()
{
foreach(搜索结果中的var sr)
{
var key=新元组(sr.Number,sr.FileName);
cache[key]=sr;
}
}

您正在一次又一次地循环搜索结果-您是否无法处理集合的“添加项目”事件?每次有更多的值进入searchResults,处理时间就会增加,这还取决于占用列表的对象是否正确实现
GetHashCode
如果每隔几秒钟运行一次函数,为什么要缓存?这有多快?第一个实例是否在下一个实例开始之前完成?可能是您在任何给定的时间点多次运行同一查询吗?而且,杰伦·海耶做了一个很好的例子point@JeroenHeier也许我的命名约定不好:)。当涉及到实际需求时,这是有意义的。我在这里用最简单的方式解释了一个复杂的场景。但我希望我的问题是清楚的。@mjwills我读了一点关于字典线程安全的书,这让我改变了主意。我已将解决方案改回使用ConcurrentDictionary。我之所以离开了重入块,是因为我确信,与updateCache方法的效率相比,OP性能问题中不受控制的线程数量即使不是更多,也是同样多的。您还需要一个自定义
IComparer
@NetMage na,我只需要使用一个
字典
,关键是数字和
文件名的
元组
,好的,你需要一个自定义的
IComparer
来使用
哈希集
:)@NetMage你不能实现Equal和GetHashCode来只查看这两个属性吗?显然,只有当这两个属性相等时,两个对象相等才有意义。是的,如果您同意。鉴于
ContainsKey
必须查找
key
,那么取消
if
并只分配给缓存不是同样有效吗?