有没有一种方法可以使用lock()
或Concurrent*
方法集来创建一个不带随机数组/列表/哈希集的方法?
我的目标:
我正在尝试创建一个从集合中完全随机选择代理的系统,该代理可以由另一个线程随时删除或添加新代理进行修改。
这里有很多“随机化”的解决方案,它们为什么不好并且不应该使用
由于多种原因,这非常不适合多线程方案。 即使将lock(){}包裹起来,并且与该集合有关的所有其他代码也可能导致修改的枚举中的冲突。 我的意思是,List可以更改其计数(可能更低),从而在选择说最终元素时导致.ElementAt引起错误,但是最终元素只是在ElementAt到达列表之前就从列表中删除了,导致异常。
另一个不好的方法是,它将在选择一个元素之前将整个列表随机化,并且容易在执行OrderBy时修改Collection导致异常。
可以通过在.OrderBy(Random)之前或执行.ElementAt之前简单地使用.ToArray()来“解决”从列表中随机选择一项的两种不良方法,但是还必须使用ToArray( )的计数。 这里的问题也是,这将对内存不利,这取决于您所做的工作,实际上是将列表的内存使用量增加了一倍。
这就是为什么我问是否有任何一种有效地随机化的方法,而不会导致多线程与集合的修改冲突。
lock = new object();
...
lock (_Lock) {
proxy = proxyArray.ElementAt(proxyArray.Count == 1 ? 0 : rand.Next(0, proxyArray.Count - 1));
}
我正在做一个计数== 1吗? 0,这样就不会浪费CPU随机数来获得明显的答案。
object proxiesRefill = new object();//for lock
...
while (!concurrentProxiesBag.TryTake(out proxy)) {//keep attempting until it takes a proxy
lock (proxiesRefill) {//it failed possibly because its empty lets lock and check on 1 thread
if (concurrentProxiesBag.IsEmpty) {//if its empty lets refill
concurrentProxiesBag = new ConcurrentBag<string>(hashsetDisabledProxies);//Refill by creating a new ConcurrentBag and adding all disabled proxies to it [Properly threadsafe? not sure]
}
}
Thread.Sleep(100);//sleep for 100ms just to cool down a small bit
}
//Got proxy
hashsetDisabledProxies.Add(proxy);//Disable proxy as its taken out of the active proxy bag by TryTake
//Its a hashset for no duplicates that could possibly get added.
答案 0 :(得分:0)
我对您的代码进行了一些更改:
while (!concurrentProxiesBag.TryTake(out proxy)) {//keep attempting until it takes a proxy
if (concurrentProxiesBag.IsEmpty) {//if its empty lets refill
concurrentProxiesBag = new ConcurrentBag<string>(hashsetDisabledProxies);//Refill by creating a new ConcurrentBag and adding all disabled proxies to it [Properly threadsafe? not sure]
}
}
Thread.Sleep(100);//sleep for 100ms just to cool down a small bit
IsEmpty, Count, ToArray(), GetEnumerator()
锁定整个结构;