<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Josef Matějka</title>
    <description>The latest articles on DEV Community by Josef Matějka (@matejjos).</description>
    <link>https://dev.to/matejjos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F677433%2F09c152d5-9a1a-4abf-94d7-3a83b300dd2a.JPG</url>
      <title>DEV Community: Josef Matějka</title>
      <link>https://dev.to/matejjos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matejjos"/>
    <language>en</language>
    <item>
      <title>Asynchronous Streams in C#</title>
      <dc:creator>Josef Matějka</dc:creator>
      <pubDate>Sat, 31 Jul 2021 08:16:55 +0000</pubDate>
      <link>https://dev.to/ciklum_czsk/asynchronous-streams-in-c-3479</link>
      <guid>https://dev.to/ciklum_czsk/asynchronous-streams-in-c-3479</guid>
      <description>&lt;h1&gt;
  
  
  C# Asynchronous streams
&lt;/h1&gt;

&lt;p&gt;I think everyone will agree that collections and data enumeration is usually bread and butter of C# programming. As a programmers we have at our disposal great tools for synchronous enumeration, we have IEnumerable and its generic variant, which can be combined with &lt;code&gt;foreach&lt;/code&gt; expression and/or with LINQ. But until C# 8.0 the options for asynchronous enumeration were limited. Iterators were strictly synchronous, thus programmers had to come up with their own solutions - the usual aproach was to create a method returning type &lt;code&gt;Task&amp;lt;IEnumerable&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;. A task that will asynchronously get a part of the collection and then synchronously enumerate it, when the task succesfully finished. In this article we will explore &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; which provides an fast and elegant solution to asynchronous enumeration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;As I said in some cases it is necesarry to load data asynchronously because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;they are behind a blocking call (files, data send through the network),&lt;/li&gt;
&lt;li&gt;or we have to wait before data are generated (like in case of &lt;code&gt;Channel&amp;lt;T&amp;gt;&lt;/code&gt;),
and we don't want to block a thread by waiting for the result. Obtaining part of data asynchronously and then enumerating the result works good from the perfomance perspective, but syntactically it can be a bit awkward and over-complicated considering how elegant does the enumeration look in case of synchronous code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  IAsyncEnumerable and IAsycnEnumerator
&lt;/h2&gt;

&lt;p&gt;I assume the reader is already familiar with &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;IEnumerator&amp;lt;T&amp;gt;&lt;/code&gt;, the asynchronous variant closesly mirrors the synchronous version, but there are few differences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GetAsyncEnumerator (counterpart of GetEnumerator) accepts a CancellationToken,&lt;/li&gt;
&lt;li&gt;MoveNextAsync (counterpart of MoveNext) returns &lt;code&gt;ValueTask&amp;lt;T&amp;gt;&lt;/code&gt; instead of T,&lt;/li&gt;
&lt;li&gt;and disposing is done via DisposeAsync instead of Dispose.&lt;/li&gt;
&lt;li&gt;Reset method is missing (but for synchronous part it is usually not implemented).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As in the case of &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;IEnumerator&amp;lt;T&amp;gt;&lt;/code&gt; programmers usually does not have to implement explicitly, but they can use iterators which will generate it. Since C# 8.0 can also generate &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;IAsyncEnumerator&amp;lt;T&amp;gt;&lt;/code&gt; via asynchronous iterators and C# provides direct support which allows you to use asynchronous stream in similar way as their synchronous counterpart. Which is why they should feel familiar, therefore it should not be problem to embrace them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating asynchronous iterator block
&lt;/h2&gt;

&lt;p&gt;Rules for the creating a asynchronous iterator with &lt;code&gt;yield return&lt;/code&gt; or &lt;code&gt;yield break&lt;/code&gt; are again analogous to the synchronous version. Your function must be of a return type &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; or &lt;code&gt;IAsyncEnumerator&amp;lt;T&amp;gt;&lt;/code&gt; it also must be &lt;code&gt;async&lt;/code&gt; function. That means no parameter can be &lt;code&gt;ref&lt;/code&gt; or &lt;code&gt;out&lt;/code&gt; and it should contain an &lt;code&gt;await&lt;/code&gt; expression. For example, consider this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;IAsyncEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;FibonacciAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;EnumeratorCancellation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;f0&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;f1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f0&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;f0&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;f1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function returns a Fibonacci sequence of all numbers that fit into an &lt;code&gt;int&lt;/code&gt;, overflow is check by this condition &lt;code&gt;if (fn &amp;lt; 1)&lt;/code&gt;, we use &lt;code&gt;Task.Delay&lt;/code&gt; for simulation of asynchronous execution, in reality the asynchronous part would be for example an database fetch or any other similar blocking operation.&lt;/p&gt;

&lt;p&gt;Since we are talking about asynchronous execution, we have to ponder a bit about cancellation of execution. If we look at &lt;code&gt;GetAsyncEnumerator&lt;/code&gt; it accepts an optional &lt;code&gt;CancellationToken&lt;/code&gt;. But in our case the &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; is generated by compiler, how can we work with a token passed to &lt;code&gt;GetAsyncEnumerator&lt;/code&gt;? If you put attribute &lt;code&gt;EnumeratorCancellation&lt;/code&gt; in front of an &lt;code&gt;CancellationToken&lt;/code&gt; argument and compiler knows that for the enumerator cancellation serves said argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enumerating throught asynchronous stream
&lt;/h2&gt;

&lt;p&gt;Let's continue by enumeration of first 5 Fibonacci's numbers. Seasoned C# programmer would immediatelly use &lt;code&gt;Take&lt;/code&gt; from &lt;code&gt;System.Linq&lt;/code&gt;. Sadly for asynchronous enumerable it is necessary to download nuget package &lt;code&gt;System.Linq.Async&lt;/code&gt; first. It contains overloads of classic extension methods for &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;. We expect that in future version of C# you will not have to download this nuget package, the methods will be automatically incorporated in base framework and no additional packages will be requiered.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;FibonacciAsync&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;WithCancellation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, C# supports asynchronous version of &lt;code&gt;foreach&lt;/code&gt; with &lt;code&gt;await&lt;/code&gt; word in front of it, the difference is that the underneath &lt;code&gt;MoveNextAsync&lt;/code&gt; calls are awaited and after finishing the enumerator is disposed asynchronously. If you need to pass a &lt;code&gt;CancellationToken&lt;/code&gt; you can do that via extension method &lt;code&gt;WithCancellation&lt;/code&gt;, which distributes the token to each internal &lt;code&gt;MoveNextAsync&lt;/code&gt; call. This token we get in our &lt;code&gt;FibonacciAsync&lt;/code&gt;, because we decorated our token argument with &lt;code&gt;EnumeratorCancellation&lt;/code&gt; attribute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance concerns
&lt;/h2&gt;

&lt;p&gt;Like in syncrhonous case, using an async iterator means, that a state machine is generated. It is represented by a hidden class implementing these interfaces: &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;IAsyncEnumerator&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;IAsyncStateMachine&lt;/code&gt;, &lt;code&gt;IValueTaskSource&amp;lt;bool&amp;gt;&lt;/code&gt;, and &lt;code&gt;IValueTaskSource&lt;/code&gt;. The reason why one class implements both &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; and &lt;code&gt;IAsyncEnumerator&amp;lt;T&amp;gt;&lt;/code&gt; is to avoid unnecessary allocations. If you have a class implementing &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; and another one implementing &lt;code&gt;IAsyncEnumerator&amp;lt;T&amp;gt;&lt;/code&gt; you need to create a new instance of enumerator each enumeration. That can be avoided if one class implement both interfaces. If no one is using the object, it can be reused as an enumerator (the same principle also goes for synchronous iterators).&lt;/p&gt;

&lt;p&gt;The main trick to keep the allocation low is to use &lt;code&gt;ValueTask&amp;lt;T&amp;gt;&lt;/code&gt; over a &lt;code&gt;Task&lt;/code&gt; and implementing &lt;code&gt;IValueTaskSource&amp;lt;bool&amp;gt;&lt;/code&gt; and &lt;code&gt;IValueTaskSource&lt;/code&gt;. As the name suggest, the &lt;code&gt;ValueTask&amp;lt;T&amp;gt;&lt;/code&gt; has value semantics (whereas classic &lt;code&gt;Task&amp;lt;T&amp;gt;&lt;/code&gt; is a reference type). This is important in cases when the &lt;code&gt;MoveNextAsync&lt;/code&gt; call runs synchronously, because in that case the &lt;code&gt;ValueTask&amp;lt;T&amp;gt;&lt;/code&gt; can be put on the stack and we can avoid heap allocation and garbage collection of this task - which hleps performance-wise. So it is expected to use async enumeration with some kind of buffering, when in asynchronous call some data are loaded and then they're returned synchronously. If you are interested in the &lt;code&gt;ValueTask&amp;lt;T&amp;gt;&lt;/code&gt; more, I recommend reading this blog post: &lt;a href="https://devblogs.microsoft.com/dotnet/understanding-the-whys-whats-and-whens-of-valuetask/"&gt;Understanding the Whys, Whats, and Whens of ValueTask&lt;/a&gt;, which explains this type and its usage in depth.&lt;/p&gt;

&lt;p&gt;Last interface &lt;code&gt;IAsyncStateMachine&lt;/code&gt; is only intended for compiler, the runtime and internal APIs uses this interface to perform awaits.&lt;/p&gt;

&lt;p&gt;The number of unecessary allocations is low, the microsoft itself states this: "The compiler implementation has been designed to keep allocations incredibly low; in fact, no matter how many times an async iterator yields, the most common case is that it incurs at most two allocations of overhead."&lt;/p&gt;

&lt;h2&gt;
  
  
  Thread safety warning
&lt;/h2&gt;

&lt;p&gt;This may be surprising to some, but in general &lt;code&gt;MoveNextAsync&lt;/code&gt; is not thread-safe. On a given enumerator each call to &lt;code&gt;MoveNextAsync&lt;/code&gt; must happen after the last &lt;code&gt;MoveNextAsync&lt;/code&gt; has finished, therefore you cannot invoke enumeration concurrently. It is not a problem for a &lt;code&gt;MoveNextAsync&lt;/code&gt; to be called from a different thread, but you must not call this function from multiple threads at the same time. The main problem is, that anything can happen. It can seem to be running correctly in some cases, in some cases an exception could be emitted. So if you want to save yourself some debugging time, stay away from enumerating &lt;code&gt;IAsyncEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; concurrently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Newly added asynchronous iterators provide a great tool for dealing with reading data collections asynchronously, this can be useful when loading data from database, files, internet or it can be usefull for in-memory collections too, like in case of Channel data structure. Plus side is, there's very small performance overhead and they closely mirror their synchronous counterpart, which makes them easier to use, because most programmers have already dealt with enumerables.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>C# Channels</title>
      <dc:creator>Josef Matějka</dc:creator>
      <pubDate>Sat, 31 Jul 2021 08:14:33 +0000</pubDate>
      <link>https://dev.to/ciklum_czsk/c-channels-mhd</link>
      <guid>https://dev.to/ciklum_czsk/c-channels-mhd</guid>
      <description>&lt;h1&gt;
  
  
  C# Channels
&lt;/h1&gt;

&lt;p&gt;The .NET Core 3.0 has brought a new namespace &lt;code&gt;System.Threading.Channels&lt;/code&gt; which contains a synchronization data structure crucial for concurrent programming. In this article I will briefly explain what concurrency is, how is it connected to &lt;code&gt;channels&lt;/code&gt;, and why is concurrency in many cases an easy way to parallel computation. It is a programing paradigm that does not necessary need mutexes, semaphores and other synchronization primitives, while it does not inherently suffer from deadlocks and race conditions. Plus, it is simple to test and reason about, because the building blocks are simple single thread oriented units.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is concurrency?
&lt;/h2&gt;

&lt;p&gt;Concurrency is a style of programming popularized mainly by Go language and its creator Rob Pike. Concurrent program means that It parts (classes/functions/methods) of the program can run with no order, independently. In our case we create classes that do some work and connect them together by a thread-safe pipeline for your data called &lt;code&gt;channel&lt;/code&gt;. Therefore we can safely send the data between the classes and we do not have to worry about making the data structures thread-safe. The safety is guaranteed by the &lt;code&gt;channels&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Concurrency does not necessary mean parallel computation, you can run a concurrent program only in one thread. But since the parts of your program are independent and can be run in any order, it is easy to transform any concurrent program to a parallel one.&lt;/p&gt;

&lt;p&gt;Let us have some analogy for channels. Imagine a little unorthodox bakery, where three workers work. Each of them is specialized in one task.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;WorkerOne&lt;/code&gt; can prepare dough,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WorkerTwo&lt;/code&gt; can bake bread,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WorkerThree&lt;/code&gt; can work at the checkout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They decided to have two baskets, &lt;code&gt;BasketOne&lt;/code&gt; is for the dough and &lt;code&gt;BasketTwo&lt;/code&gt; is for the bread and they agreed to this algorithm of work.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When &lt;code&gt;WorkerOne&lt;/code&gt; is done, he puts dough into the &lt;code&gt;BasketOne&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WorkerTwo&lt;/code&gt; will take dough from the basket whenever he can and starts working,&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;WorkerTwo&lt;/code&gt; is done, he puts the bread into the &lt;code&gt;BasketTwo&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WorkerThree&lt;/code&gt; will take the bread from the basket and puts it on the counter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The baskets here represent channels, the product is safely stored in a basket until it is needed. All workers are synchronized by the baskets, if a basket is full, the worker has to wait until it is empty again. When the basket is empty and the worker has nothing to do, he must wait until the basket is filled again. But otherwise, they can work independently. And if they find out, that &lt;code&gt;WorkerTwo&lt;/code&gt; is a bottleneck for their production, they can always hire a worker with the same specialization and just like that they made the process of baking faster - no other change is necessary, they just need one more worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Example
&lt;/h2&gt;

&lt;p&gt;Imagine you want to program a concurrent prime sieve (inspired by &lt;a href="https://play.golang.org/p/9U22NfrXeq"&gt;Go channel tutorial&lt;/a&gt;), to demonstrate how you can utilize channels in your C# program. First we need to identify our independent parts of the program. Let us create two classes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generator - generates natural numbers from 2,&lt;/li&gt;
&lt;li&gt;Filter - checks if a number is divisible by a prime number.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generator class could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Generator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ChannelReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;//from here other classes will get a next natural number&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBounded&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;//we create a channel with capacity 1&lt;/span&gt;
        &lt;span class="n"&gt;Reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//runs task Generate.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChannelWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="c1"&gt;//puts a natural number into the channel, waits if the channel is full&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a instance of Generator gets initialized, it will run a task on background, which&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;puts a natural number i into the channel,&lt;/li&gt;
&lt;li&gt;increases i by one,&lt;/li&gt;
&lt;li&gt;waits until the channel is empty again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Filter on the other hand could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Filter&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ChannelReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;//from here will other filters get a next potential prime number&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChannelReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;primeNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBounded&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;//we create a channel with capacity 1&lt;/span&gt;
        &lt;span class="n"&gt;Reader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;FilterLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primeNumber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//runs task FilterLoop&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;FilterLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ChannelReader&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ChannelWriter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;primeNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllAsync&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="c1"&gt;//reads a value if available, otherwise waits&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="n"&gt;primeNumber&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//checks if i is divisible by primeNumber&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="c1"&gt;//puts non-divisible number into the writer&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When an instance of filter is created, the FilterLoop task will do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;reads a number from the ChannelReader,&lt;/li&gt;
&lt;li&gt;tries to divide it by a prime number,

&lt;ol&gt;
&lt;li&gt;if it is divisible it waits for the next number,&lt;/li&gt;
&lt;li&gt;if it is not divisible, it will write it into the output channel,&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;waits for the next number.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The main method then can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;primeReader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt; &lt;span class="c1"&gt;//the loop will print the first ten prime numbers&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;prime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;primeReader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsync&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ConfigureAwait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Prime number: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prime&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;primeReader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;primeReader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the main loop we connect the &lt;code&gt;ChannelReader&lt;/code&gt; from &lt;code&gt;Generator&lt;/code&gt; instance with the first &lt;code&gt;Filter&lt;/code&gt; instance. Then we take the reader from the last filter and connect it to the new instance of &lt;code&gt;Filter&lt;/code&gt;. So we end up with a chain of channels, where the Generator generates natural numbers and each filter tests if a number can be prime. Here is a simple diagram to demonstrate the workflow:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi02aoif0iau5n10zy158.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi02aoif0iau5n10zy158.png" alt="Workflow" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First &lt;code&gt;i&lt;/code&gt; that passes all filters is the next prime number. Therefore we can print it and use it as a argument for a new &lt;code&gt;Filter&lt;/code&gt; instance. Each instance can run independently. If there is something in the input, it will process it, otherwise it will wait in background not blocking any thread.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unbounded variant
&lt;/h2&gt;

&lt;p&gt;In the example above we have worked with bounded channels, but C# also offers a unbounded variant. The API is the same, but the &lt;code&gt;ChannelWriter&lt;/code&gt; will not wait in &lt;code&gt;WriteAsync&lt;/code&gt; function - because the channel is never full. This can lead to an exception when the memory is full. I would recommend to use this channel when you know that output of generator (the part that uses ChannelWriter) is somehow limited and we are sure that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we have enough memory,&lt;/li&gt;
&lt;li&gt;we don't need to limit generator's throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider what would happen if we used unbounded &lt;code&gt;Channel&lt;/code&gt; in &lt;code&gt;Generator&lt;/code&gt; class. Since the generator class can generate a new number wihout any waiting, the default C# &lt;code&gt;TaskScheduler&lt;/code&gt; has no reason to run the Generate function asynchronously, therefore the &lt;code&gt;Channel&lt;/code&gt; would be filled by integers until the memory is full and a memory exception is thrown. As you can see using unbounded channels can be potentionally dangerous if we are not careful enough. For that reason I recommend use bounded channels by default and switch to the unbounded ones only when necessary. Since the in the unbounded variant there is no waiting on write, there is no need for &lt;code&gt;TaskScheduler&lt;/code&gt; to intervene, which could result in faster computation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why C# even needs channels?
&lt;/h2&gt;

&lt;p&gt;You could argue that we do not need channels at all. In the example we could just use TPL in combination with async/await and build an asynchronous prime sieve that would be doing the exact same thing. Of course you avoid channels and use other tools C# provides to build parallel programs. But from my experience it seems that in some cases it is easier to reason, test and scale concurrent programs.&lt;/p&gt;

&lt;p&gt;In the current project I am working on, we have noticed that using channels simplifies parallelism, because we only need to create and test few simple classes and then connect them via channels. With almost no effort we end with correct parallel programs. We do not have to be afraid of deadlock, race conditions, we do not have to think how to make our clasess thread safe. Other big advantage is if any class in the concurrent program seems to be a bottleneck. For example if we notice our &lt;code&gt;ChannelReader&lt;/code&gt; is most of the time full, we can always spawn another instance of it and connect it to the &lt;code&gt;ChannelReader&lt;/code&gt; and with almost no effort we have made our application faster. &lt;/p&gt;

&lt;p&gt;If the channel data structure interests you, I recommend to read through &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.threading.channels"&gt;Microsoft documentation&lt;/a&gt; and look at Rob Pike's presentations &lt;a href="https://www.youtube.com/watch?v=oV9rvDllKEg&amp;amp;t=3s"&gt;Concurrency is not parallelism&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=f6kdp27TYZs&amp;amp;t=2214s"&gt;Go Concurrency patterns&lt;/a&gt;. Eventhought the presentations are aimed for Golang the same principles apply to C#.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>computerscience</category>
    </item>
  </channel>
</rss>
