C#面试题更新 2026-08-05

请描述在 C# 中借助 BlockingCollection 来构建一个容量受限的缓冲区的方法,并说明其工作原理与常见用法。

编码实现技术原理C#

考察说明

考查对 BlockingCollection 的异步阻塞特性以及实现有界缓冲区的理解。

回答思路

  1. 【回答框架 1】BlockingCollection 是 .NET 中用于线程安全的生产者消费者集合,构造时可通过 BoundedCapacity 指定最大容量。当集合达到上限时,生产者调用 Add 会阻塞,直到有空间;消费者调用 Take 或 TryTake 时,若集合为空则阻塞等待,从而自动实现背压与流量控制。
  2. 【回答框架 2】典型用法是创建 BlockingCollection<int> buffer = new BlockingCollection<int>(boundedCapacity: 10); 生产者循环调用 Add,消费者循环调用 Take。通过 GetConsumingEnumerable 可以迭代取出所有元素,该枚举在 CompleteAdding 之后会结束。
  3. 【回答框架 3】需要在使用完毕后调用 CompleteAdding 来通知消费者不再有更多元素,这能避免消费者一直阻塞。注意:调用 CompleteAdding 后不能再次添加元素,否则会抛异常。
  4. 【回答框架 4】对于超时或取消需求,可以使用 TryAdd(T item, TimeSpan timeout, CancellationToken token) 和 TryTake(out T item, TimeSpan timeout, CancellationToken token) 等重载,配合 CancellationToken 实现合作式取消,避免无限阻塞。
  5. 【回答框架 5】在多生产者多消费者场景下,BlockingCollection 默认使用 ConcurrentQueue 作为底层集合,保证线程安全;也可以指定其他符合 IProducerConsumerCollection 的集合,如 ConcurrentStack 或 ConcurrentBag,以改变策略。
  6. 【关键点 1】容量限制通过 BoundCapacity 参数实现,满时 Add 阻塞。
  7. 【关键点 2】使用 CompleteAdding 通知消费者结束。
  8. 【关键点 3】可通过 GetConsumingEnumerable 简化消费者循环。
  9. 【易错点 1】不要在调用 CompleteAdding 后继续调用 Add,否则会引发异常。
  10. 【易错点 2】若忘记调用 CompleteAdding,消费者线程可能永远阻塞。
  11. 【易错点 3】注意区分 Add 与 TryAdd:TryAdd 可指定超时,不会无限阻塞。