线程安全随机数组

时间:2018-10-15 21:19:19

标签: c# multithreading

有没有一种方法可以使用lock()Concurrent*方法集来创建一个不带随机数组/列表/哈希集的方法?

我的目标:

  • 能够根据需要添加和删除字符串(或能够添加和“禁用”字符串)
  • 能够清除列表或换掉整个字符串集
  • 无需使用.ElementAt和.Count / .Count()的随机值,就可以从中获取项目(类似于TryPeek的种类)以随机选择任何项目

我正在尝试创建一个从集合中完全随机选择代理的系统,该代理可以由另一个线程随时删除或添加新代理进行修改。

这里有很多“随机化”的解决方案,它们为什么不好并且不应该使用

.ElementAt(Random.Next(List.Count))不是将列表随机化的好方法

由于多种原因,这非常不适合多线程方案。 即使将lock(){}包裹起来,并且与该集合有关的所有其他代码也可能导致修改的枚举中的冲突。 我的意思是,List可以更改其计数(可能更低),从而在选择说最终元素时导致.ElementAt引起错误,但是最终元素只是在ElementAt到达列表之前就从列表中删除了,导致异常。

.OrderBy(Random)

另一个不好的方法是,它将在选择一个元素之前将整个列表随机化,并且容易在执行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随机数来获得明显的答案。

我尝试使用ConcurrentBag

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.

1 个答案:

答案 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()锁定整个结构;