簡體   English   中英

無法從 BlockingCollection 檢索數據塊<t></t>

[英]Cannot retrieve chunks of data from BlockingCollection<T>

我經常發現自己確實想要 stream 塊中的數據而不是一個接一個。 通常我在需要執行一些基於 I/O 的操作時這樣做,比如我想限制往返的數據庫插入。 所以我得到了這個不錯的小擴展方法:

        public static IEnumerable<List<T>> Split<T>(this IEnumerable<T> data, int size)
        {            
            using (var enumerator = data.GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    yield return YieldBatchElements(enumerator, size - 1).ToList();
                }
            }

            IEnumerable<TU> YieldBatchElements<TU>(
                IEnumerator<TU> source,
                int batchSize)
            {
                yield return source.Current;
                for (var i = 0; i < batchSize && source.MoveNext(); i++)
                {
                    yield return source.Current;
                }
            }
        }

這工作得很好,但我注意到它不適用於BlockCollection<T> GetConsumingEnumerable

我創建了以下測試方法來證明我的發現:

        [Test]
        public static void ConsumeTest()
        {
            var queue = new BlockingCollection<int>();
            var i = 0;
            foreach (var x in Enumerable.Range(0, 10).Split(3))
            {
                Console.WriteLine($"Fetched chunk: {x.Count}");
                Console.WriteLine($"Fetched total: {i += x.Count}");
            }
            //Fetched chunk: 3
            //Fetched total: 3
            //Fetched chunk: 3
            //Fetched total: 6
            //Fetched chunk: 3
            //Fetched total: 9
            //Fetched chunk: 1
            //Fetched total: 10
         

            Task.Run(
                () =>
                    {
                        foreach (var x in Enumerable.Range(0, 10))
                        {
                            queue.Add(x);
                        }
                    });

            i = 0;
            foreach (var element in queue.GetConsumingEnumerable(
                new CancellationTokenSource(3000).Token).Split(3))
            {
                Console.WriteLine($"Fetched chunk: {element.Count}");
                Console.WriteLine($"Fetched total: {i += element.Count}");
            }

            //Fetched chunk: 3
            //Fetched total: 3
            //Fetched chunk: 3
            //Fetched total: 6
            //Fetched chunk: 3
            //Fetched total: 9
        }

顯然,如果元素少於塊大小,則最后一個塊將被“丟棄”。 有任何想法嗎?

我們應該調用CompleteAdding()方法來通知GetConsumingEnumerable()沒有更多的元素可以從其生產者添加。

以下代碼更改將解決您的問題並打印缺失的行。

Task.Run(() =>
              {
                 foreach (var x in Enumerable.Range(0, 10))
                 {
                    queue.Add(x);
                 }
                    queue.CompleteAdding(); // After executing the line, IsCompleted property of queue will be true.
              });

有關 BlockingCollection 的 GetConsumingEnumerable() 的更多信息,請參閱鏈接。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM