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
并只分配给缓存不是同样有效吗?