C# C-IEnumerable选择1个随机元素CPU使用率

C# C-IEnumerable选择1个随机元素CPU使用率,c#,C#,是否可以从IEnumerable中选择1个随机元素,而不直接将所有元素加载到内存中 我试图从17000个KeyValuePairs的列表中挑选一个随机代理,循环中每秒两次 KeyValuePairs是:string、bool。其中string是代理,bool是是否禁用的 concDict == ConcurrentDictionary<string, bool> (btw) IEnumerable<KeyValuePair<string, bool>> tem

是否可以从IEnumerable中选择1个随机元素,而不直接将所有元素加载到内存中


我试图从17000个KeyValuePairs的列表中挑选一个随机代理,循环中每秒两次

KeyValuePairs是:string、bool。其中string是代理,bool是是否禁用的

concDict == ConcurrentDictionary<string, bool> (btw)
IEnumerable<KeyValuePair<string, bool>> temp = concDict.Where(p => !p.Value);
activeProxies = temp.Count();
proxy = temp.ElementAt(proxyRandom.Next(0, activeProxies - 1)).Key;
以上是我到目前为止的情况。这里的问题是它会导致大量CPU使用。下图来自大约10秒的CPU评测

也许LINQ.Where's或.Count的东西正在渲染所有元素?若有的话,是否有一种方法可以在Bool设置为false的元素上创建如图所示的ElementAt

我现在唯一能想到的办法,就是不用。在哪里做,在一段时间内做。很有可能,它会击中一个错误的,但当几乎所有的错误都是真的时,它的表现会比where差得多。 因为ElementAt randomizer的activeProxies计数不是最新的,所以它甚至不起作用。

在这里使用IEnumerable是错误的。取而代之的是,使用一个列表——它可以让您更快地计数和选择一个随机项目,并且CPU使用率也要少得多:

// this enumerate the dictionary one and the result of the where once.
List<KeyValuePair<string, bool>> temp = concDict.Where(p => !p.Value).ToList(); 
// now this will be a lot faster...
activeProxies = temp.Count;
proxy = temp.[proxyRandom.Next(0, activeProxies - 1)].Key;

关于您的问题,如果不计算IEnumerable之前的所有成员,则不可能随机选择IEnumerable的一个成员。正如其他成员在评论中所说,您当前的代码枚举两次:获取活动代理,然后获取它们的计数。可能是第三次跳过随机数,但不确定实现细节

在我看来,一个更好的解决方案是使用ConcurrentDictionary,这样可以更快地获得一个活动的随机代理,而不必反复枚举。17k条目不需要担心在内存中加载太多数据,特别是它们是简单类型,并且不是很大

dictionary.AddOrUpdate(
  true,
  new List<string>() {"new proxy"},
  (b, list) => {
    list.Add("new proxy";
    return list;
});
如果键不存在,这将添加列表;如果键存在,则会将字符串添加到列表中。
您可以使用空列表初始化字典,并将其作为第二个参数传递null,以减少每次调用时创建新列表的成本,但只有在您确定字典已初始化时才可以这样做。

我不知道,您是否尝试过对其进行索引?@ZohirSalakCeNa index?在中,元素本身有一个int,我可以使用它来引用?那怎么办?我还是不能把它们随机化。除非我在这里没有正确思考:/n否则您将枚举集合两次。一次用于您的.811行,然后再次使用.Where。为什么不在activeProxies子集合的.ElementAt中只枚举一次activeProxies?为什么使用Dictionary而不是Dictionary?第二种方法可以更容易地过滤掉不活动的代理,也可以更容易地随机选择一个活动代理。你也可以使用Dictionary@ImPRAGMA在列表中选择一个随机元素,而不仅仅是第一个,背后的驱动力是什么?我有点怀疑,总体而言,它会快得多。使用ToList将项目复制到新数组中不是免费的。我试图在循环中每秒两次从17000个KeyValuePairs的列表中随机选取一个代理。虽然这比一次使用ElementAt和Count要糟糕得多,但是如果您每秒使用ElementAt两次,您可能会受益于一次重载操作.ToList和多个轻量级操作,使用列表的索引器(与IEnumerable的ElementAt类似)。好的,但是您需要将该列表与主词典同步,因为在两次检查之间,它可能已更改,并且在列表中处于活动状态并标记为活动状态的代理可能已死亡。@Evk这一点很好。在这种情况下,最好直接从字典中选择一个随机成员,或者首先使用列表而不是字典,或者使用两个列表,一个用于活动代理,一个用于死亡代理。但我没能让OP澄清他是否真的需要字典。编辑:nvm,但我该如何更新它?例如,向列表中添加新值或从列表中删除值?我不需要重新编译整个列表吗?你可以使用addorUpdateKey, TValue, Func方法。根据项目本身,您可以使用普通DictionaryRight,但是我如何移动一个TValue,现在它是一个列表而不是字符串,让TKey作为true的TValue呢?像id一样,基本上需要得到true的列表,并将其添加到列表中,然后将其发送回。我敢打赌,那一定会很慢。我基本上不得不这样补充,没有更好的办法吗?您传递的函数将更新现有列表。不确定您的意思。