BlockingCollection的TryTake遇空集合返回false而非阻塞,求原因
TryTake Behavior in BlockingCollection<T> Let's walk through the most likely causes for your TryTake method returning false instead of blocking until an item is available, even with an unbounded collection and active producers:
Producers prematurely called
CompleteAdding()
This is the most common culprit. OnceCompleteAdding()is invoked on theBlockingCollection<T>, it signals that no more items will be added. Even if you set a timeout,TryTakewill immediately returnfalsewhen the collection is empty, since it knows no new items are coming. Double-check your producer code to ensure this method is only called after all items have been successfully added to the collection.Invalid timeout value passed to your
TryTakewrapper
Your wrapper accepts atimeoutMilisecondsparameter, but if this value is0(immediate return) or incorrectly set to a very short duration,TryTakewon't wait long enough for a producer to add an item. If you want indefinite blocking, make sure you passTimeout.Infinite(-1) when calling your wrapper method.The underlying
_collectioninstance was disposed or replaced
If theBlockingCollection<T>instance stored in_collectiongets disposed (e.g., via a using statement that's too broad) or reinitialized to a new empty collection, subsequentTryTakecalls will fail immediately. Verify that_collectionremains intact and undisposed for the entire lifecycle of your producer-consumer workflow.Producer operations aren't actually adding items to the collection
Even if you've set a reasonable timeout forTryAdd, there could be hidden issues preventing producers from adding items:- Producers might be hitting exceptions before reaching the
TryAddcall. - If
CompleteAdding()was called early,TryAddwill returnfalseeven for an unbounded collection, so no items get added at all. - Producer threads might be terminated or stuck before completing their add operations.
- Producers might be hitting exceptions before reaching the
To debug this further, you can modify your wrapper method to log additional state before throwing the exception:
public T TryTake(int timeoutMiliseconds) { var result = default(T); if (!_collection.TryTake(out result, timeoutMiliseconds)) { // Log these values to diagnose the state var isAddingCompleted = _collection.IsAddingCompleted; var currentCount = _collection.Count; throw new InvalidOperationException($"Unable to get item from collection. IsAddingCompleted: {isAddingCompleted}, CurrentCount: {currentCount}"); } return result; }
内容的提问来源于stack exchange,提问作者ilans

