ConcurrentQueue和Parallel.ForEach

时间:2016-06-11 21:07:40

标签: c# parallel.foreach concurrent-queue

我有一个ConcurrentQueue,其中包含我需要获取源代码的URL列表。当使用带有ConcurrentQueue对象的Parallel.ForEach作为输入参数时,Pop方法不会工作(应该返回一个字符串)。

我使用Parallel并将MaxDegreeOfParallelism设置为4。我真的需要阻止并发线程的数量。使用具有Parallelism冗余的队列吗?

提前致谢。

// 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);
        }
    }

2 个答案:

答案 0 :(得分:4)

如果您要做的只是首先从单个帖子中添加项目然后在ConcurrentQueue<T>中进行迭代,那么您不需要Parallel.ForEach()。正常List<T>就足够了。

此外,您对ItemQueue的实施非常可疑:

  • 它继承自ConcurrentQueue<string>,还包含另一个ConcurrentQueue<string>。这没有多大意义,令人困惑和低效。

  • ConcurrentQueue<T>上的方法设计得非常谨慎,以确保线程安全。您的Pop()不是线程安全的。可能发生的情况是您检查Count,注意它1,然后拨打TryDequeue()并且没有获得任何价值(即value将是null),因为另一个线程在两次调用之间的时间内从队列中删除了该项。

答案 1 :(得分:0)

问题在于CrawlItems方法,因为您不应该在为ForEach方法提供的操作中调用Pop。原因是在每个弹出的项目上调用操作,因此该项目已经弹出。这就是动作有一个'item'参数的原因。

我假设你因为ForEach方法已经被其他线程弹出所有项目而变为null。

因此,您的代码应如下所示:

 select *  from tbl_Product a inner join tbl_images b on a.id = b.prd_id