我有一个ConcurrentQueue,其中包含要获取其来源的URL列表。当将Parallel.ForEach与ConcurrentQueue对象用作输入参数时,Pop方法将无效(应返回一个字符串)。
我正在使用MaxDegreeOfParallelism设置为4的Parallel。我真的需要阻止并发线程的数量。使用具有并行性的队列是否多余?
提前致谢。
// On the main class
var items = await engine.FetchPageWithNumberItems(result);
// Enqueue List of items
itemQueue.EnqueueList(items);
var crawl = Task.Run(() => { engine.CrawlItems(itemQueue); });
// On the Engine class
public void CrawlItems(ItemQueue itemQueue)
{
Parallel.ForEach(
itemQueue,
new ParallelOptions {MaxDegreeOfParallelism = 4},
item =>
{
var worker = new Worker();
// Pop doesn't return anything
worker.Url = itemQueue.Pop();
/* Some work */
});
}
// Item Queue
class ItemQueue : ConcurrentQueue<string>
{
private ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public string Pop()
{
string value = String.Empty;
if(this.queue.Count == 0)
throw new Exception();
this.queue.TryDequeue(out value);
return value;
}
public void Push(string item)
{
this.queue.Enqueue(item);
}
public void EnqueueList(List<string> list)
{
list.ForEach(this.queue.Enqueue);
}
}
最佳答案
如果您要做的只是先从单个线程向其中添加项目,然后在ConcurrentQueue<T>
中进行迭代,则不需要Parallel.ForEach()
。普通的List<T>
就足够了。
另外,您对ItemQueue
的实现非常可疑:
它继承自ConcurrentQueue<string>
,还包含另一个ConcurrentQueue<string>
。那没有多大意义,令人困惑且效率低下。ConcurrentQueue<T>
上的方法经过精心设计,以确保线程安全。您的Pop()
不是线程安全的。可能发生的情况是,您检查Count
,注意它是1,然后调用TryDequeue()
却没有任何值(即value
将是null
),因为另一个线程在两次调用之间从队列中删除了该项目。这两个电话。
关于c# - ConcurrentQueue和Parallel.ForEach,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37768526/