堆堆 發表於 2023-2-28 09:32:00

C#神器"BlockingCollection"类实现C#神仙操作

<h2 id="前言">前言</h2>
<p>如果你想玩转C# 里面多线程,工厂模式,生产者/消费者,队列等高级操作,就可以和我一起探索这个强大的线程安全提供阻塞和限制功能的<strong>C#神器类</strong></p>
<h3 id="blockingcollection简单介绍">BlockingCollection简单介绍</h3>
<p>微软介绍地址:https://learn.microsoft.com/zh-cn/dotnet/standard/collections/thread-safe/blockingcollection-overview<br>
<strong>BlockingCollection</strong> 是一个线程安全集合类,可提供以下功能:</p>
<ol>
<li>实现制造者-使用者模式</li>
<li>通过多线程并发添加和获取项</li>
<li>可选最大容量</li>
<li>集合为空或已满时通过插入和移除操作进行阻塞</li>
<li>插入和移除“尝试”操作不发生阻塞,或在指定时间段内发生阻塞</li>
<li>封装实现 IProducerConsumerCollection 的任何集合类型</li>
<li>使用取消标记执行取消操作</li>
<li>支持使用 foreach(在 Visual Basic 中,使用 For Each)的两种枚举:1. 只读枚举,2. 在枚举项时将项移除的枚举</li>
</ol>
<h3 id="起手式">起手式</h3>
<blockquote>
<p>BlockingCollection<string> blockingCollection = new(1);</string></p>
<ul>
<li>new 操作符里面的数字是实现了<strong>可选最大容量</strong>,超出就线程阻塞了,程序一直卡在哪里</li>
</ul>
</blockquote>
<h3 id="先来个开胃菜--三句代码实现线程阻塞">先来个开胃菜 =&gt; 三句代码实现线程阻塞</h3>
<pre><code class="language-csharp">BlockingCollection&lt;int&gt; blockingCollection = new(1);
blockingCollection.Add(1);
blockingCollection.Add(2);
</code></pre>
<blockquote>
<p>说明:因为限制队列只能插入一条,第一条没有消费掉,所以一直卡在插入第二条程序不会往下继续运行实现了<strong>集合为空或已满时通过插入和移除操作进行阻塞</strong></p>
</blockquote>
<h3 id="正式开始前先分享一些多线程的知识点">正式开始前先分享一些多线程的知识点</h3>
<h4 id="task类简单介绍"><strong>Task类简单介绍</strong></h4>
<blockquote>
<p>Task 表面上是Thread但却是对ThreadPool的封装,控制和扩展性很强,对线程的延续,阻塞,取消,超时,比传统的Thread和ThreadPool强</p>
</blockquote>
<h4 id="queue类简单介绍"><strong>Queue类简单介绍</strong></h4>
<blockquote>
<p>队列(Queue)代表了一个先进先出的对象集合。当您需要对各项进行先进先出的访问时,则使用队列。当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队</p>
</blockquote>
<h3 id="接下来进入实际使用场景">接下来进入实际使用场景</h3>
<h3 id="场景一-生产者-消费者">场景一: 生产者=&gt; 消费者</h3>
<blockquote>
<p>建议代码还是要动手实现一下,不然体会不到一边生产数据,同时还能取数据的神仙操作</p>
</blockquote>
<pre><code class="language-csharp">int count = 0 ;
BlockingCollection&lt;string&gt; blockingCollection = new(1);
//生产者
Task.Factory.StartNew(() =&gt;
{
while (true)
{
    blockingCollection.Add("String: " + count);
    count++;
    if (count &gt; 10)
    {
   blockingCollection.CompleteAdding();
    }
}
});

//消费者
Task.Factory.StartNew(() =&gt;
{
foreach (var element in blockingCollection.GetConsumingEnumerable())
{
Thread.Sleep(1000);
("Work: " + element).Dump();//Dump 为工具Linq的功能
}
});
</code></pre>
<blockquote>
<p>上面的代码中这个方法<code>GetConsumingEnumerable</code>很重要,它可以在BlockingCollection<t>集合有数据的时候取数据,没有的话停止取,可以达到监测的效果</t></p>
</blockquote>
<p><strong>这个案例实现了如下功能:</strong></p>
<ol>
<li>多线程并发添加和获取项</li>
<li>生产者和消费者模式</li>
<li>使用取消标记执行取消操作(让生产者知道我们已经不需要你工作了)</li>
</ol>
<h3 id="生产者消费者输出结果">生产者/消费者输出结果</h3>
<pre><code class="language-text">Work: String: 0
Work: String: 1
Work: String: 2
Work: String: 3
Work: String: 4
Work: String: 5
Work: String: 6
Work: String: 7
Work: String: 8
Work: String: 9
Work: String: 10
</code></pre>
<h3 id="场景二-实现队列fifo先进先出lifo先进后出">场景二: 实现队列FIFO(先进先出),LIFO(先进后出)</h3>
<pre><code class="language-csharp"> //先进先出(FIFO)
BlockingCollection&lt;int&gt; bc = new(new ConcurrentQueue&lt;int&gt;());
bc.Add(1);
bc.Add(2);
bc.CompleteAdding();

//先进后出(LIFO)
BlockingCollection&lt;int&gt; bc2 = new(new ConcurrentStack&lt;int&gt;());
bc2.Add(1);
bc2.Add(2);
bc2.CompleteAdding();

bc.Take().Dump("bc1:");
bc2.Take().Dump("bc2:");
</code></pre>
<h3 id="队列输出结果">队列输出结果</h3>
<pre><code class="language-text">bc :1
bc2: 2
</code></pre>
<blockquote>
<p>这个简单的案例是想介绍一下其实:<strong>BlockingCollection也可以实现队列的功能</strong></p>
</blockquote>
<h4 id="以上就是本期的全部内容啦谢谢大家看到这里">以上就是本期的全部内容啦谢谢大家看到这里</h4>
<h5 id="作者--百宝门瞿佑明">作者 =&gt; 百宝门瞿佑明</h5>
<p>原文地址:https://blog.baibaomen.com/c神器blockingcollection类实现c神仙操作/</p><br><br>
来源:https://www.cnblogs.com/baibaomen-org/p/17162795.html
頁: [1]
查看完整版本: C#神器"BlockingCollection"类实现C#神仙操作