[__DynamicallyInvokable]
public IEnumerable<T> GetConsumingEnumerable(CancellationToken cancellationToken)
{
...
while (!this.IsCompleted)
{
T obj;
if (this.TryTakeWithNoTimeValidation(out obj, -1, cancellationToken, linkedTokenSource))
yield return obj;
}
...
}
и
public bool TryTake(out T item)
{
...
return this.TryTakeWithNoTimeValidation(out item, (int) timeout.TotalMilliseconds, CancellationToken.None, (CancellationTokenSource) null);
}
оба метода TryTake и GetConsumingEnumerable используют метод TryTakeWithNoTimeValidation. Я предполагаю, что отсутствующие элементы были удалены из коллекции с помощью GetConsumingEnumerable. рассмотрим следующий пример:
private static void Producer()
{
Console.WriteLine($"begin produce isCompleted:{_bc.IsCompleted}");
for (var i = 0; i < 5000; i++)
_bc.Add($"msg:{i}");
_bc.CompleteAdding();
Console.WriteLine($"end produce isCompleted:{_bc.IsCompleted}");
}
var batch = new List<string>();
foreach (var s in _bc.GetConsumingEnumerable())
{
batch.Add(s);
if (_bc.IsCompleted && _bc.Count == 0)
{
break;
}
}
Console.WriteLine($"first:{batch.First()}, last:{batch.Last()}");
Console.WriteLine($"consumed:{batch.Count}");
_bc пусто.
Есть несколько способов реализовать ваш алгоритм, один из которых я рекомендую использовать Take и вызывать потребителя перед производителем (который блокирует вызывающий поток).