BlockingCollection 运行 上的 foreach 循环为何以及如何无限循环?

Why and how does a foreach-loop on BlockingCollection run infinite?

我正在开发一个简单的文件记录器,遇到了线程安全问题,并且正在研究其他人是如何做的。 我遇到了使用 BlockingCollection 作为队列和 foreach 循环来处理该队列的方法:

var queue = new BlockingCollection<string>(1024);
var t = Task.Factory.StartNew(() => {
                                        foreach (var message in queue.GetConsumingEnumerable()) {
                                            WriteMessageToFile(message);
                                        }
                                    }, TaskCreationOptions.LongRunning);

Dim queue = New BlockingCollection(Of String)(1024)
Dim t = Task.Factory.StartNew(Sub()
                                  For Each message In queue.GetConsumingEnumerable()
                                      WriteMessageToFile(message)
                                  Next
                              End Sub, TaskCreationOptions.LongRunning)

这个 For Each 循环实际上 运行 是无限的。它处理我添加到 queue 的数据,直到我在 BlockingCollection 上调用 .CompleteAdding

我想知道为什么会这样,以及如何以及是否是一个好方法。 当集合为空时线程会做什么,它会检查每个滴答声吗?这不是资源繁重吗?

它使用 SemiphoreSlim 等待 GetConsumingEnumerable 并在添加项目时调用 Release(高度简化)。

SemaphoreSlim is a lightweight alternative to the Semaphore class that doesn't use Windows kernel semaphores

https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=netcore-3.1

您可以在此处阅读 BlockingCollection 的完整代码:https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs