LINQ on循环条件

时间:2015-06-04 13:29:20

标签: c# .net linq loops iteration

假设我有以下代码:

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),只调用一次,然后每次迭代使用原始结果,还是在每个迭代步骤中处理?

4 个答案:

答案 0 :(得分:4)

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

第二:这段代码存在缺陷。

  1. LINQ使用延迟执行。换句话说,在迭代 allKeys时,底层数据(在您的情况下为_cache)正在被迭代。与删除相结合,这不会起作用。
  2. _cache最有可能是普通词典或类似的词典。换句话说,它不是线程安全的。更新:根据评论,它是ObjectCache类型,并且该类型确实是线程安全的。因此,在您的具体情况下,此问题不会发生。

答案 1 :(得分:4)

  

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

不,你没有。由于称为延迟执行的内容,您存储的所有内容都是获取所有密钥的命令。您需要具体化此命令才能实际执行您认为的操作:

  

var allKeys = _cache.Select(o =&gt; o.Key) .ToList();

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

如果你坚持让所有这一切都在一行,你可以使用PLINQ:

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

但是又一次:这似乎是一个坏主意。

答案 2 :(得分:1)

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

保存查询和循环...

答案 3 :(得分:0)

首先,你不能在迭代时修改一个集合,这就是.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));

将在密钥的副本上工作。 <{1}}类型是线程安全的,ObjectCache也是如此,所以你应该没问题。

此处唯一的潜在问题是此代码是否位于多线程应用程序(如Web应用程序)中。让多个线程能够读取/写入/从缓存中删除会打开大量蠕虫,并使用锁来强制管理缓存访问。