LINQ on循环条件

本文关键字:条件 循环 on LINQ | 更新日期: 2023-09-27 17:53:26

假设我有以下代码:

IEnumerable<string> allKeys = _cache.Select(o => o.Key);
Parallel.ForEach(allKeys, key => _cache.Remove(key));

如您所见,我正在检索_cache中的所有键,将它们存储在我的局部变量allKeys中,然后同时从_cache中删除所有键。

我想用一行来写。所以我想到的是:

Parallel.ForEach(_cache.Select(o => o.Key), key => _cache.Remove(key));

但是语句_cache.Select(o => o.Key)将在每次循环迭代中调用,因此每次检索不同数量的元素(因为我同时删除了它们)。

后一行代码安全吗?

循环中_cache.Select(o => o.Key)语句只被调用一次,然后每次迭代使用原始结果,还是在每个迭代步骤中处理?

LINQ on循环条件

可以看到,我正在检索_cache中的所有键,并将它们存储在本地变量allKeys

不,你不需要。由于所谓的延迟执行,您存储的只是获取所有键的命令。您需要实现这个命令,以便实际执行您认为应该执行的操作:

var allKeys = _cache。Select(o => o. key).ToList();

也就是说:你的缓存线程安全吗?为什么它没有一个Clear方法?通过使用多线程获取所有密钥并删除它似乎不是一个好主意。

如果你坚持要把它们都放在一行中,你可以使用PLINQ:

_cache.Select(o => o.Key).AsParallel().ForAll(key => _cache.Remove(key));

首先,两个代码是相同的。有没有临时变量是没有区别的。

第二:这个代码有缺陷。

    LINQ使用延迟执行。换句话说,当迭代 allKeys时,底层数据(在您的例子中是_cache)正在被迭代。与remove结合使用,这将不起作用。
  1. _cache很可能是一个普通的字典或类似的东西。换句话说,它不是线程安全的。更新:根据注释,它的类型是ObjectCache,并且该类型确实是线程安全的。所以这个问题不会发生在你的具体情况下。

它不是更有效的Dispose你现有的_cache对象,只是重新创建它,而不是单独删除每个项目?

首先,您不能在遍历集合时修改它,这是.Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)在幕后所做的。所以这一行

Parallel.ForEach(_cache.Select(o => o.Key), key => _cache.Remove(key));

将无法工作。

你可以试试这个

Parallel.ForEach(_cache.Select(o => o.Key).ToList(), key => _cache.Remove(key));

,它将在密钥的副本上工作。ObjectCache类型是线程安全的,MemoryCache也是,所以你应该没问题。

这里唯一的潜在问题是,如果这段代码是在多线程应用程序中(如Web应用程序)。如果有多个线程可以对缓存进行读/写/删除操作,就会产生一个巨大的问题,并且强制使用锁来管理缓存访问。