Analysis of asynchronous iterator iasyncenumerable in C # 8

Time:2021-7-19

Asynchronous programming has been popular for many years. The async and await keywords introduced by. Net make asynchronous programming more readable. However, there is a pity that before C # 8, asynchronous processing of data streams can not be used until C # 8IAsyncEnumerableOnly then solved this problem.

Speaking ofIAsyncEnumerableWe have to talk about it firstIEnumerableAs we all know, it iterates over the collection collection collection in a synchronous way, and theIAsyncEnumerableIn other words:IAsyncEnumerableThe calling thread is not blocked during the iteration of the collection.

IAsyncDisposable, IAsyncEnumerable, IAsyncEnumerator

Asynchronous iteratorIt allows us to process data asynchronously. Before that, we need to understand the following three interfaces:Iasyncdisposable, iasyncenumerable and iasyncenumeratorThey are all introduced in. Net standard 2.1. The following code fragment shows the definition of these three interfaces.

public interface IAsyncDisposable
{
    ValueTask DisposeAsync();
}

public interface IAsyncEnumerable
{
    IAsyncEnumerator GetAsyncEnumerator(CancellationToken
    token = default);
}

public interface IAsyncEnumerator : IAsyncDisposable
{
    ValueTask MoveNextAsync();
    T Current { get; }
}

Why use asynchronous iterators

Imagine that you have a data access layer that needs to read all the data from the database at one time. To use this function, you can directly call the asynchronous method provided by the underlying layerXXXAsycImplement asynchronous call and return all data at one time.

As long as not all the data are presented on the page, the problem of this solution is not too big, and most of the time, it is throughPaging readIn fact, a better way to do this is to return the data to the caller immediately when it is available.

To be exact, you can use asynchronous iterators here. If your method is synchronous return, you can use asynchronous iteratorsreturn yield+Return valueIEnumerableUnfortunately, this method is not extensible because it needs to block the calling thread.

The best solution isreturn yield+Return valueIAsyncEnumerableThe asynchronous iterator method returns theIAsyncEnumerableInstance, and can contain one or moreyield returnsentence.

Creating asynchronous iterators in C × 8

The following code snippet shows a returnTask>Type, as shown in the following code:

class Program
    {
        const int DELAY = 1000;
        const int MIN = 1;
        const int MAX = 10;

        public static async Task Main(string[] args)
        {
            foreach (int number in await GetData())
            {
                Console.WriteLine($"{DateTime.Now}: number={number}");
            }

            Console.ReadLine();
        }

        public static async Task> GetData()
        {
            List integers = new List();
            for (int i = MIN; i <= MAX; i++)
            {
                await Task.Delay(DELAY);
                integers.Add(i);
            }
            return integers;
        }
    }

When running the above application, it will wait 10 seconds before putting all the 1-10 digital outputs on the console, although thisGetDataIt’s asynchronous, but in the end, it’s one-time output instead of one second output.

At this time, you can let yield keyword intervene. It is introduced in C # 2.0 and is often used for executionState iterationAnd return data from the collection one by one. You don’t need to create a set (integers) as above to return to it. The following code fragment is the version that modifies the GetData method and merges the yield keyword. The code is as follows:

static async IAsyncEnumerable GetData()
{
   for (int i = MIN; i < MAX; i++)
   {
      yield return i;
      await Task.Delay(DELAY);  
   }
}

Using asynchronous iterator in C × 8

To useAsynchronous flow, you need to add an await keyword before foreach, as shown in the following code:

public static async Task Main(string[] args)
        {
            await foreach (int number in GetData())
            {
                Console.WriteLine($"{DateTime.Now}: number={number}");
            }

            Console.ReadLine();
        }

Here is the complete code for reference only.

class Program
    {
        const int DELAY = 1000;
        const int MIN = 1;
        const int MAX = 10;

        public static async Task Main(string[] args)
        {
            await foreach (int number in GetData())
            {
                Console.WriteLine($"{DateTime.Now}: number={number}");
            }

            Console.ReadLine();
        }

        static async IAsyncEnumerable GetData()
        {
            for (int i = MIN; i < MAX; i++)
            {
                yield return i;
                await Task.Delay(DELAY);
            }
        }
    }

A very important feature of C # 8 is supportIAsyncEnumerableIt can make your application code cleaner, more efficient and more performance.

More wonderful, welcome to subscribe

Translation link:https://www.infoworld.com/article/3531251/how-to-use-asynchronous-streams-in-csharp-80.html

Recommended Today

Detailed explanation of how to customize redis command with Lua

preface As a very successful database, redis provides a wealth of data types and commands. Using these, we can easily and efficiently complete many cache operations, but there are always some special problems or needs to be solved. At this time, we may need to customize our own redis data structure and commands. Redis command […]