4

ソースを取得する必要がある URL のリストを含む ConcurrentQueue があります。ConcurrentQueue オブジェクトを入力パラメーターとして Parallel.ForEach を使用すると、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);
        }
    }
4

2 に答える 2

6

ConcurrentQueue<T>最初に 1 つのスレッドから項目を追加してから、Parallel.ForEach(). それにはノーマルList<T>で十分でしょう。

また、あなたの実装ItemQueueは非常に疑わしいです:

  • から継承しConcurrentQueue<string>、別の も含みますConcurrentQueue<string>。それはあまり意味がなく、混乱を招き、非効率的です。

  • のメソッドは、ConcurrentQueue<T>スレッドセーフになるように非常に慎重に設計されています。あなたPop()はスレッドセーフではありません。2 つの呼び出しの間に別のスレッドがキューからアイテムを削除したため、をチェックCountし、それが 1 であることを確認してから、 を呼び出しTryDequeue()て値を取得しない (つまり、valueになる)ことが起こり得ます。null

于 2016-07-10T00:56:04.587 に答える