首页 新闻 会员 周边

C# 阻塞队列 BlockingCollection<T> 是否会长期占用一个线程?

0
[待解决问题]

文档地址:
https://learn.microsoft.com/zh-cn/dotnet/api/system.collections.concurrent.blockingcollection-1?source=recommendations&view=net-7.0

当该集合中没有内容时, TryTake 方法会阻塞. 可用于"实现生产-消费模式".

那么是否意味着阻塞时,也会有一个线程会被占用?

有没有能在阻塞时将线程还给线程池,需要用时再重新从线程池中取线程的替代品呢?

谢谢.

xiejiang的主页 xiejiang | 菜鸟二级 | 园豆:202
提问于:2023-04-14 17:17
< >
分享
所有回答(3)
1

可以使用 TryAddTryTake,详见 Timed Blocking Operations

dudu | 园豆:30948 (高人七级) | 2023-04-14 17:29

文档读了好几遍竟然把这里漏掉了, 谢谢.

支持(0) 反对(0) xiejiang | 园豆:202 (菜鸟二级) | 2023-04-17 08:41
0

考虑用Channel替换实现, Channel能更好的用在Task/async/await模式下.

czd890 | 园豆:14412 (专家六级) | 2023-04-17 11:03
0

是的,当阻塞队列 BlockingCollection<T> 中没有元素可供 TryTake 方法取出时,该方法会阻塞线程。这意味着该线程会被占用,直到有元素可以被取出。

不过,BlockingCollection<T> 内部使用的是信号量(Semaphore)来实现阻塞和唤醒,而不是简单的忙等待(busy-waiting)。这意味着阻塞队列内部不会一直忙碌地等待元素的到来,而是会暂时释放占用的线程,并在有新元素到来时重新唤醒线程。这样就能更有效地利用系统资源。

如果你想要在阻塞时将线程还给线程池,可以考虑使用异步方法 TakeAsync,它会返回一个 Task 对象,可以在需要时 await 这个任务并在异步上下文中执行。这样就可以在等待时释放线程,并在有新元素到来时重新恢复执行。具体代码可以参考下面的示例:

arduino

async Task ConsumeAsync(BlockingCollection<int> queue)
{
while (true)
{
// 使用异步方式等待元素的到来
int item = await queue.TakeAsync();

    // 处理元素
    Console.WriteLine(item);
}

}

Technologyforgood | 园豆:5698 (大侠五级) | 2023-04-17 20:11
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册