[英]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.